對象鎖,鎖的是類的對象實例。java
類鎖 ,鎖的是每一個類的的Class對象,每一個類的的Class對象在一個虛擬機中只有一個,因此類鎖也只有一個。express
適合於只有一個線程寫,多個線程讀的場景,由於它只能確保可見性。ide
線程變量。能夠理解爲是個map,類型 Map<Thread,Integer>this
難以保證及時性,資源開銷很大,spa
wait() 對象上的方法,將是當前執行線程進行等待。線程
notify/notifyAll 對象上的方法 發送信號量,喚醒線程。code
代碼示例:對象
/** * @Auther: BlackKingW * @Date: 2019/4/14 12:09 * @Description: */ public class Express { public final static String CITY = "ShangHai"; private int km;/*快遞運輸里程數*/ private String site;/*快遞到達地點*/ public Express() { } public Express(int km, String site) { this.km = km; this.site = site; } /* 變化千米數,而後通知處於wait狀態並須要處理千米數的線程進行業務處理*/ public synchronized void changeKm(){ this.km = 101; notifyAll(); //其餘的業務代碼 } /* 變化地點,而後通知處於wait狀態並須要處理地點的線程進行業務處理*/ public synchronized void changeSite(){ this.site = "BeiJing"; notify(); } public synchronized void waitKm(){ while(this.km<=100) { try { wait(); System.out.println("check km thread["+Thread.currentThread().getId() +"] is be notifed."); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("the km is"+this.km+",I will change db."); } public synchronized void waitSite(){ while(CITY.equals(this.site)) { try { wait(); System.out.println("check site thread["+Thread.currentThread().getId() +"] is be notifed."); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("the site is"+this.site+",I will call user."); } } /** * @Auther: BlackKingW * @Date: 2019/4/14 12:09 * @Description: */ public class TestWN { private static Express express = new Express(0,Express.CITY); /*檢查里程數變化的線程,不知足條件,線程一直等待*/ private static class CheckKm extends Thread{ @Override public void run() { express.waitKm(); } } /*檢查地點變化的線程,不知足條件,線程一直等待*/ private static class CheckSite extends Thread{ @Override public void run() { express.waitSite(); } } public static void main(String[] args) throws InterruptedException { for(int i=0;i<3;i++){//三個線程 new CheckSite().start(); } for(int i=0;i<3;i++){//里程數的變化 new CheckKm().start(); } Thread.sleep(1000); express.changeKm();//快遞地點變化 } }
等待和通知的標準範式ip
等待方:資源
通知方來講
notify和notifyAll應該用誰?
應該儘可能使用notifyAll,使用notify由於有可能發生信號丟失的的狀況
thread.Join把指定的線程加入到當前線程,能夠將兩個交替執行的線程合併爲順序執行的線程。
好比在線程B中調用了線程A的Join()方法,直到線程A執行完畢後,纔會繼續執行線程B。
代碼示例:
/** * @Auther: BlackKingW * @Date: 2019/4/14 12:09 * @Description: */ public class UseJoin { // static class JumpQueue implements Runnable { private Thread thread;//用來插隊的線程 public JumpQueue(Thread thread) { this.thread = thread; } public void run() { try { System.out.println(thread.getName()+" will be join before " +Thread.currentThread().getName()); thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" terminted."); } } public static void main(String[] args) throws Exception { Thread previous = Thread.currentThread();//如今是主線程 for (int i = 0; i < 10; i++) { //i=0,previous 是主線程,i=1;previous是i=0這個線程 Thread thread = new Thread(new JumpQueue(previous), String.valueOf(i)); System.out.println(previous.getName()+" jump a queue the thread:" +thread.getName()); thread.start(); previous = thread; } SleepTools.second(2);//讓主線程休眠2秒 System.out.println(Thread.currentThread().getName() + " terminate."); } }
線程在執行yield()之後,持有的鎖是不釋放的
sleep()方法被調用之後,持有的鎖是不釋放的
調動方法以前,必需要持有鎖。調用了wait()方法之後,鎖就會被釋放,當wait方法返回的時候,線程會從新持有鎖
調動方法以前,必需要持有鎖,調用notify()方法自己不會釋放鎖的