1. 線程使用run()和start()有什麼區別
直接使用run(),是將線程對象當做普通對象來處理,那麼run()相當於執行了一個普通對象實例的普通方法。線程只有主線程一個。
而start(),則會啓動一個新的線程。
public class TestThread implements Runnable {
public void run() {
System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getThreadGroup());
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
Thread t2 = new Thread(new TestThread());
Thread t3 = new Thread(new TestThread());
t1.run();
t2.run();
t3.run();
System.out.println(Thread.currentThread().getName());
}
}
public void run() {
System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getThreadGroup());
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
Thread t2 = new Thread(new TestThread());
Thread t3 = new Thread(new TestThread());
t1.run();
t2.run();
t3.run();
System.out.println(Thread.currentThread().getName());
}
}
執行結果:
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
main
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
main
使用start()方法
public class TestThread implements Runnable {
public void run() {
System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getThreadGroup());
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
Thread t2 = new Thread(new TestThread());
Thread t3 = new Thread(new TestThread());
t1.start();
t2.start();
t3.start();
System.out.println(Thread.currentThread().getName());
}
}
public void run() {
System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getThreadGroup());
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
Thread t2 = new Thread(new TestThread());
Thread t3 = new Thread(new TestThread());
t1.start();
t2.start();
t3.start();
System.out.println(Thread.currentThread().getName());
}
}
執行結果:
Thread[Thread-0,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
main
Thread[Thread-2,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[Thread-1,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
main
Thread[Thread-2,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[Thread-1,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
注意,打印語句的順序有可能發生變化。
2 sleep()方法與wait()方法的區別
sleep()方法是Thread類的方法,而wait()方法則是Object類的方法。某個線程調用sleep()方法是休眠一定時間,在這段時間裏,並不釋放已獲得的對象鎖。而wait()方法則阻塞當前線程,並釋放已獲得的對象鎖。(爲什麼wait()方法一定要釋放對象鎖,因爲wait()方法有可能長時間不被喚醒,如果它一直佔用對象鎖,那就麻煩大了)。
實例說明sleep()一直佔用對象鎖。
public class BankAccount {
private long balance;
public synchronized void setBalance(long balance) {
this.balance = balance;
}
public synchronized long getBalance() {
System.out.println("balance .... " + this.balance);
return balance;
}
public synchronized void save() {
try {
Thread.currentThread().sleep(1000);
} catch(InterruptedException e) {
}
this.balance = this.balance + 1000;
System.out.println("save 1000");
}
public synchronized void draw() {
this.balance = this.balance - 1000;
System.out.println("draw 1000");
}
}
private long balance;
public synchronized void setBalance(long balance) {
this.balance = balance;
}
public synchronized long getBalance() {
System.out.println("balance .... " + this.balance);
return balance;
}
public synchronized void save() {
try {
Thread.currentThread().sleep(1000);
} catch(InterruptedException e) {
}
this.balance = this.balance + 1000;
System.out.println("save 1000");
}
public synchronized void draw() {
this.balance = this.balance - 1000;
System.out.println("draw 1000");
}
}
再創建一個線程類進行測試
public class OperateThread implements Runnable {
private BankAccount account;
private String operating;
public void run() {
operate();
}
public void operate() {
if (operating.equals("save")) {
this.account.save();
} else {
this.account.draw();
}
}
public OperateThread(BankAccount account, String operating) {
this.account = account;
this.operating = operating;
}
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread save = new Thread(new OperateThread(account, "save"));
Thread draw = new Thread(new OperateThread(account, "draw"));
save.start();
draw.start();
}
}
private BankAccount account;
private String operating;
public void run() {
operate();
}
public void operate() {
if (operating.equals("save")) {
this.account.save();
} else {
this.account.draw();
}
}
public OperateThread(BankAccount account, String operating) {
this.account = account;
this.operating = operating;
}
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread save = new Thread(new OperateThread(account, "save"));
Thread draw = new Thread(new OperateThread(account, "draw"));
save.start();
draw.start();
}
}
輸出結果如下所示:
save 1000
draw 1000
draw 1000
可見,save()方法sleep()了1000ms,draw()必須等待save()執行完畢。
將draw()方法的synchronized修飾詞去掉。
public class BankAccount {
private long balance;
public synchronized void setBalance(long balance) {
this.balance = balance;
}
public synchronized long getBalance() {
System.out.println("balance .... " + this.balance);
return balance;
}
public synchronized void save() {
try {
Thread.currentThread().sleep(1000);
} catch(InterruptedException e) {
}
this.balance = this.balance + 1000;
System.out.println("save 1000");
}
public void draw() {
this.balance = this.balance - 1000;
System.out.println("draw 1000");
}
}
private long balance;
public synchronized void setBalance(long balance) {
this.balance = balance;
}
public synchronized long getBalance() {
System.out.println("balance .... " + this.balance);
return balance;
}
public synchronized void save() {
try {
Thread.currentThread().sleep(1000);
} catch(InterruptedException e) {
}
this.balance = this.balance + 1000;
System.out.println("save 1000");
}
public void draw() {
this.balance = this.balance - 1000;
System.out.println("draw 1000");
}
}
再次執行,輸出結果如下,
draw 1000
save 1000
save 1000
此時draw()不會等待save()執行完畢。
使用wait()來改寫BankAccount類。
public class BankAccount {
private long balance;
public synchronized void setBalance(long balance) {
this.balance = balance;
}
public synchronized long getBalance() {
System.out.println("balance .... " + this.balance);
return balance;
}
public synchronized void save() {
try {
wait();
} catch(InterruptedException e) {
}
this.balance = this.balance + 1000;
System.out.println("save 1000");
}
public synchronized void draw() {
this.balance = this.balance - 1000;
System.out.println("draw 1000");
notifyAll();
}
}
private long balance;
public synchronized void setBalance(long balance) {
this.balance = balance;
}
public synchronized long getBalance() {
System.out.println("balance .... " + this.balance);
return balance;
}
public synchronized void save() {
try {
wait();
} catch(InterruptedException e) {
}
this.balance = this.balance + 1000;
System.out.println("save 1000");
}
public synchronized void draw() {
this.balance = this.balance - 1000;
System.out.println("draw 1000");
notifyAll();
}
}
輸出結果如下所示,
draw 1000
save 1000
save 1000
可見,save()方法阻塞了進程,但是draw()仍然可以執行。
3,什麼是對象監視器。
Java中內置了對併發訪問的支持機制,每個對象都有一個監視器,在同一時刻,只允許一個線程獲得監視器,並訪問對象的同步方法。其他線程必須等待對象監視器被釋放才能訪問對象的同步方法,但是可以隨時訪問其它非同步方法。
這裏的對象是指,創建線程時,所使用的target對象。
例如,Thread t = new Thread(target)中的target。
Thread如何獲得對象監視器呢?Thread通過調用對象的同步方法即可獲得對象監視器。
所以,一旦某個Thread調用了對象的synchronized方法,那麼其他線程將無法調用該對象的任何synchronized方法。
4 什麼是守護進程
守護進程也是進程,爲什麼叫它守護進程呢?它並不是守護某個其他的進程或對象。這裏的守護跟程序執行完畢,JVM退出有關。
JVM退出有兩種方式,一是所有進程都執行完畢,JVM自動退出;二是執行System.exit(0)直接退出。
在第一種情況下,所有進程執行完畢是指,所有用戶進程執行完畢。當然,線程分用戶線程和守護線程兩類。用戶線程會限制JVM,不能在用戶線程執行完畢之前正常退出。而守護線程則不會限制JVM。
舉例來說,
public class TestThread implements Runnable {
public void run() {
// System.out.println(Thread.currentThread() + ":" +
// Thread.currentThread().getThreadGroup());
for (int i = 1; i < 11; i++) {
try {
Thread.currentThread().sleep(15);
} catch (InterruptedException e) {
}
System.out.println("Current Time ........................... = "
+ i);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
// Thread t2 = new Thread(new TestThread());
// Thread t3 = new Thread(new TestThread());
// t1.setDaemon(true);
t1.start();
// t2.start();
// t3.start();
System.out.println(Thread.currentThread().getName());
}
}
public void run() {
// System.out.println(Thread.currentThread() + ":" +
// Thread.currentThread().getThreadGroup());
for (int i = 1; i < 11; i++) {
try {
Thread.currentThread().sleep(15);
} catch (InterruptedException e) {
}
System.out.println("Current Time ........................... = "
+ i);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
// Thread t2 = new Thread(new TestThread());
// Thread t3 = new Thread(new TestThread());
// t1.setDaemon(true);
t1.start();
// t2.start();
// t3.start();
System.out.println(Thread.currentThread().getName());
}
}
t1作爲一個用戶線程,只有當其執行完畢,JVM纔會退出。
輸出結果如下所示:
main
Current Time ........................... = 1
Current Time ........................... = 2
Current Time ........................... = 3
Current Time ........................... = 4
Current Time ........................... = 5
Current Time ........................... = 6
Current Time ........................... = 7
Current Time ........................... = 8
Current Time ........................... = 9
Current Time ........................... = 10
Current Time ........................... = 1
Current Time ........................... = 2
Current Time ........................... = 3
Current Time ........................... = 4
Current Time ........................... = 5
Current Time ........................... = 6
Current Time ........................... = 7
Current Time ........................... = 8
Current Time ........................... = 9
Current Time ........................... = 10
將t1設置爲守護線程時,代碼如下所示:
public class TestThread implements Runnable {
public void run() {
// System.out.println(Thread.currentThread() + ":" +
// Thread.currentThread().getThreadGroup());
for (int i = 1; i < 11; i++) {
try {
Thread.currentThread().sleep(15);
} catch (InterruptedException e) {
}
System.out.println("Current Time ........................... = "
+ i);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
// Thread t2 = new Thread(new TestThread());
// Thread t3 = new Thread(new TestThread());
t1.setDaemon(true);
t1.start();
// t2.start();
// t3.start();
System.out.println(Thread.currentThread().getName());
}
}
public void run() {
// System.out.println(Thread.currentThread() + ":" +
// Thread.currentThread().getThreadGroup());
for (int i = 1; i < 11; i++) {
try {
Thread.currentThread().sleep(15);
} catch (InterruptedException e) {
}
System.out.println("Current Time ........................... = "
+ i);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
// Thread t2 = new Thread(new TestThread());
// Thread t3 = new Thread(new TestThread());
t1.setDaemon(true);
t1.start();
// t2.start();
// t3.start();
System.out.println(Thread.currentThread().getName());
}
}
此時的輸出結果如下所示:
main
Current Time ........................... = 1
Current Time ........................... = 2
Current Time ........................... = 3
Current Time ........................... = 1
Current Time ........................... = 2
Current Time ........................... = 3
可見,輸出只打印了10條語句中的3條。