Java多線程技術-wait/notify/join,-waitnotify
wait/notify的作用
wait()方法的作用是使當前執行代碼的線程進行等待,wait()是Object類的方法,用來將當前線程置入預執行隊列中,並且在wait()所在的代碼處停止執行,直到接到通知或被中斷為止。wait()調用前,必須獲得該對象的對象級鎖,即只能在同步方法或者同步代碼塊中調用wait()方法,否則會拋出IllegalMonitorStateException。當wait()執行後,當前線程釋放鎖
notify()方法的作用是用來通知那些可能等待該對象的對象鎖的其他線程,如果有多個線程等待,則隨機挑選出一個wait狀態的線程,對其發出通知,並使它等待擷取該對象的對象鎖。notify()調用前,必須獲得該對象的對象級鎖,即只能在同步方法或者同步代碼塊中調用notify()方法,否則會拋出IllegalMonitorStateException。當notify()方法執行後,不會馬上釋放該對象的鎖,呈wait狀態的線程也並不能馬上獲得該對象鎖,要等到執行notify()的線程將程式執行完,也就是退出synchronized代碼塊後,當前線程才會釋放鎖。
notifyAll()方法和notify()作用基本是一樣的,一個是喚醒全部的wait線程,一個是喚醒其中一個wait線程。
經典案例生產者和消費者
public class MyStack { private List<String> list = new ArrayList<>(); public synchronized void push() { try { while (list.size() == 1) { System.out.println("push:"+Thread.currentThread().getName()+"呈wait狀態"); this.wait(); } list.add("anyString=" + Math.random()); this.notifyAll(); System.out.println("push=" + list.size()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public synchronized String pop(){ String returnValue = ""; try { while(list.size() == 0){ System.out.println("pop:"+Thread.currentThread().getName()+"呈wait狀態"); this.wait(); } returnValue = list.get(0); list.remove(0); this.notifyAll(); System.out.println("pop="+list.size()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return returnValue; }}public class Product { private MyStack myStack; public Product(MyStack myStack) { this.myStack = myStack; } public void pushService(){ myStack.push(); }}public class Customer { private MyStack myStack; public Customer(MyStack myStack) { this.myStack = myStack; } public void popService(){ myStack.pop(); }}public class ThreadCustomer extends Thread { private Customer customer; public ThreadCustomer(Customer customer) { this.customer = customer; } @Override public void run() { while(true){ customer.popService(); } }}public class ThreadProduct extends Thread { private Product product; public ThreadProduct(Product product) { this.product = product; } @Override public void run() { while(true){ product.pushService(); } }}public class Test { public static void main(String[] args) throws InterruptedException { MyStack myStack = new MyStack(); Product p = new Product(myStack); Customer c = new Customer(myStack); ThreadProduct pThread = new ThreadProduct(p); ThreadCustomer cThread = new ThreadCustomer(c); pThread.start(); cThread.start(); }}View Code
join的作用
join()是Thread類的一個方法,它的作用是使所屬的線程x對象正常的執行run方法中的任務,而使當前線程z進行無限期的阻塞,等待線程x銷毀後再繼續執行線程z後面的代碼。
public class MyThread extends Thread{ @Override public void run() { try { System.out.println(System.currentTimeMillis()); Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}public class Test { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); myThread.join(); System.out.println("在myThread執行完後輸出:" + System.currentTimeMillis()); }}View Code
測試結果:
1516170164683在myThread執行完後輸出:1516170167686
join和synchronized的區別
從上面的例子可以看出,join方法具有線程排隊啟動並執行作用,有些類是同步的運行效果。join和synchronized的區別是:join在內部使用wait()方法進行等待,而synchronized是使用“對象監視器”原理做為同步
join(long)和sleep(long)的區別
由於join的內部是使用wait來實現的,所以它具有釋放鎖的特點,而sleep沒有這一特點。
源碼如下:
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }