等待&喚醒
關於Object類提供的wait、notify、notifyAll三個方法:ide
wait():讓當前線程處於等待(阻塞)狀態,直到其餘線程調用該同步監視器的notify(),notifyAll()方法來喚醒該線程,進入就緒狀態。wait()會釋放對當前線程的同步監視器的鎖定。this
—>無時間參數的wait:一直等到,直到其餘線程通知喚醒spa
—>帶時間參數的wait:等待指定時間後自動喚醒。線程
notify():喚醒在此同步監視器上等待的單個線程。若監視器上有不少個線程等待,則任意喚醒一個。code
notifyAll:喚醒在此同步監視器上等待的全部線程。對象
wait¬ify示例:blog
class Thread2 extends Thread{ public Thread2(String name) { super(name); } @Override public void run(){ synchronized (this) { System.out.println(Thread.currentThread().getName()+" call notify()"); //喚醒當前的wait線程 notify(); } } } public class WaitTest { public static void main(String[] args) throws InterruptedException { Thread2 t = new Thread2("t2"); synchronized (t) { //啓動線程 t.start(); //讓線程等待 System.out.println("wait"); t.wait(); } } }
主線程main經過實例化獲取線程t,隨後經過synchronized(t)獲取t對象的同步鎖,以後調用start方法啓動線程t。get
主線程main經過執行t.wait()釋放t的同步鎖,進入了「等待(阻塞)狀態」,等待t對象經過notify喚醒「當前對象上等待的線程」,也就是主線程。同步
wait和notify之間依賴於同步鎖,而同步鎖是對象持有的,所以這幾個方法屬於Object。
it
線程中斷
中斷方式:
—>終止處於「阻塞狀態」的線程
當線程調用了yield、join、sleep等方法進入阻塞狀態,若此時調用線程的interrupt()方法,將線程中斷標記設置爲true,處於阻塞狀態,中斷標記將被清除同時產生一個IntertuptedException異常,將異常放在適合的位置將會終止線程。
@Override public void run() { try { while (true){ //to-do } }catch(InterruptedException ie){ // 產生InterruptedException異常,退出while循環,線程終止 } }
—>終止處於「運行狀態」的線程
1)經過「中斷標記」中斷線程
@Override public void run() { while (!isInterruped()){ //....... } }isInterrupted是判斷線程中的中斷標記是否爲true
2)經過「額外標記」中斷線程
private volatile boolean flag = true; @Override public void run() { while (flag){ //....... } }
優先級
Java中的優先級範圍是1-10:
MAX_PRIORITY:10
MIN_PRIORITY:1
NOR_PRIORITY:5(默認)
能夠經過setPriority()改變線程的優先級,高優先級的線程將會得到更多執行的機會。
守護線程
Java的線程分爲兩種:用戶線程和守護線程(後臺線程),能夠用isDaemon()方法來區別:若是返回false則爲用戶線程,不然爲守護線程,JVM的垃圾回收線程就是典型的守護線程(後臺線程)
後臺線程的特徵:若是前臺線程都死亡,後臺線程會自動死亡。
能夠用setDaemon(true)將指定線程設定爲後臺線程。
class Daemon extends Thread{ //後臺線程的設定與普通線程並無任何區別 @Override public void run() { for (int i = 0; i < 10 ; i++) { System.out.print(Thread.currentThread().getName()+"-"+i); } } } public class Test { public static void main(String[] args) { Daemon d = new Daemon(); //將線程設置爲守護線程 d.setDaemon(true); //啓動線程 d.start(); for (int i = 0; i < 10 ; i++) { System.out.println(Thread.currentThread().getName()+" "+i+" "); } //線程執行到此,前臺線程(main)執行結束 //後臺線程也跟着結束 } }
主線程默認爲前臺線程。前臺線程建立的子線程默認爲前臺線程,後臺線程建立的子線程默認爲後臺線程。
前臺死亡以後JVM會通知後臺後臺線程死亡,並且須要必定時間。要將某個線程設置爲後臺線程必定要在該線程啓動以前設置。
也就是說setDaemon(true)要在start以前,不然將會報IllegalThreadStateException異常。