线程之间的协作
当多个线程一起工作的时候,可能线程与线程之间存在执行的先后顺序,所以需要对线程进行协调。
join()
在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。
public class JoinExemple {
public class A extends Thread{
@Override
public void run(){
System.out.println("A run");
}
}
public class B extends Thread{
private A a;
B(A a){
this.a=a;
}
@Override
public void run(){
try{
a.join();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("B run");
}
}
public static void main(String[]args){
JoinExemple e=new JoinExemple();
A a=e.new A();
B b=e.new B(a);
b.start();
a.start();
}
}
wait(),notify(),notifyAll()
wait(),notify(),notifyAll()是Object类的方法,不是线程的方法,调用wait()使得线程满足某个条件后才能够继续运行,此时该线程会挂起,当另外的线程执行使得这个条件满足时会调用notify(),notifyAll()方法唤醒挂起的线程。
wait(),notify(),notifyAll()只能在同步块或者同步方法中使用否则在运行时抛出 IllegalMonitorStateException。
使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class WaitNotifyExemple {
public class WaitExemple{
public synchronized void before(){
System.out.println("before");
notifyAll();
}
public synchronized void after(){
try{
wait();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("after");
}
}
public static void main(String[]args){
WaitNotifyExemple e=new WaitNotifyExemple();
WaitExemple exemple=e.new WaitExemple();
ExecutorService executorService= Executors.newCachedThreadPool();
executorService.execute(()->exemple.after());
executorService.execute(()->exemple.before());
executorService.shutdown();
}
}
wait()和sleep()区别
wait()是Object方法,sleep()是Thread方法,wait()会释放锁,而sleep()不会。
await(),signal(),signalAll()
java.until.concurrent包中提供了Condition类来实现线程之间的协调,可以调用await()方法使线程等待,其他的线程调用signal或者signalAll方法唤醒等待的线程。
相比wait(),await()可以指定等待的条件,因此更加的灵活,使用Lock来获取一个Condition对象。
package ConcurrentExemple;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AwaitSignalExemple {
public class AwaitExemple{
Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();
public void before(){
lock.lock();
try {
System.out.println("before");
condition.signalAll();
}finally {
lock.unlock();
}
}
public void after(){
lock.lock();
try{
condition.await();
System.out.println("after");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public static void main(String[]args){
AwaitSignalExemple e=new AwaitSignalExemple();
AwaitExemple waitExemple=e.new AwaitExemple();
ExecutorService executorService= Executors.newCachedThreadPool();
executorService.execute(()->waitExemple.after());
executorService.execute(()->waitExemple.before());
executorService.shutdown();
}
}