The role of wait/notify
The function of the wait() method is to make the thread currently executing the code wait. wait() is a method of the Object class that places the current thread in the pre-execution queue and stops execution at the code where wait() is located until it is notified or interrupted. Before calling wait(), you must obtain the object-level lock of the object, that is, you can only call wait() method in the synchronization method or the synchronization code block, otherwise IllegalMonitorStateException will be thrown. When wait() executes, the current thread releases the lock
The notify() method is used to notify other threads that may wait for the object lock. If multiple threads wait, a thread in wait state is randomly selected, notified, and made wait for the object lock to be acquired. Before notify() is called, the object-level lock of the object must be obtained, that is, the notify() method can only be called in the synchronization method or the synchronization code block, otherwise IllegalMonitorStateException will be thrown. When the notify() method is executed, the lock of the object will not be released immediately, nor can the thread in wait state get the lock of the object immediately. The current thread will not release the lock until the thread executing notify() has finished executing the program, that is, after exiting the synchronized code block.
NotfyAll () method and notify() function basically the same, one is to wake up all wait threads, the other is to wake up one of the wait threads.
Classic case producers and consumers
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()+"present wait state"); 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()+"present wait state"); 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(); } }
The role of join
join() is a method of the Thread class. Its function is to make the thread x object normal to perform the tasks in the run method, and make the current thread z block indefinitely, waiting for thread x to destroy before continuing to execute the code after thread 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("stay myThread Output after execution:" + System.currentTimeMillis()); } }
Test results:
1516170164683 Output after myThread execution: 1516170167686
The difference between join and synchronized
As can be seen from the examples above, join method has the function of thread queuing, and some classes have the effect of synchronization. The difference between join and synchronized is that join waits internally using wait() method, while synchronized uses the principle of "object monitor" as synchronization.
The difference between join(long) and sleep(long)
Because the inside of join is implemented by wait, it has the characteristics of releasing locks, which sleep does not have.
The source code is as follows:
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;
}
}
}