线程协作
当多个线程一起工作解决某个问题的时候,如果某些线程必须在其他线程完成之后裁可以继续,那么久需要对线程进行协调。通常由以下几种方式
方式一:调用线程 join()方法
在一个线程调用另外一个线程的 join()方法, 会将当前线程挂起,直到目标线程结束
public class JoinSychronization {
private class AThread extends Thread {
private String name;
public AThread(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("执行A线程 " + name);
}
}
private class BThread extends Thread {
private AThread aThread;
private String name;
public BThread(AThread aThread,String name) {
this.aThread = aThread;
this.name = name;
}
@Override
public void run() {
try {
aThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行B线程方法 " + name);
}
}
public void test() {
AThread thread = new AThread("demoA");
BThread demoB = new BThread(thread, "demoB");
demoB.start();
thread.start();
}
public static void main(String[] args) {
JoinSychronization sychronization = new JoinSychronization();
sychronization.test();
}
}
备注:
- test 方法中,虽然说 demoB 线程先启动, 但是 demoB 线程调用了 thread 线程的 join()方法,所以 demoB 线程会等待 thread 线程结束裁继续执行, 所以先输出 执行 A 线程 demoA, 之后输出 执行 B 线程方法 demoB
运行结果如下:
执行A线程 demoA
执行B线程方法 demoB
方式二:通过 Object wait()/notify()/notifyAll()协调
调用 wait() 使线程等待某个条件满足,线程在等待的时候会被挂起,当其他线程线程的运行使这个条件满足时,其他线程会调用 notify() 或者 notifyAll() 唤醒挂起的线程, 需要注意的是,只能在同步方法或者同步控制块才能使用,否则会抛出 IllegalMonitorStateException, wait()挂起,线程会释放锁,否则其他线程就无法进入对象的同步方法或者同步控制块,那么久无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程, 会造成死锁
notify() 跟 notifyAll()的区别:
唤醒数量不同
notify()方法只会随机唤醒等待队列中的一个线程,而 notifyAll()方法则会唤醒等待队列中的所有线程。
竞争情况不同
notify()方法只会唤醒等待队列中的一个线程,并使其与其他线程竞争获取锁,这可能会导致某些线程无法被唤醒或者一直处于等待状态。 notifyAll()方法则会唤醒等待队列中的所有线程,并使它们竞争获取锁,这样可以使所有线程都有机会获取锁并进入运行状态,从而避免了一些线程一直处于等待状态。
public class WaitNotifySychonization {
public synchronized void begin() {
System.out.println("开始执行");
notifyAll();
}
public synchronized void end() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束执行");
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
WaitNotifySychonization waitNotifySychonization = new WaitNotifySychonization();
executorService.execute(waitNotifySychonization::end);
executorService.execute(waitNotifySychonization::begin);
Thread.sleep(2000);
executorService.shutdown();
}
}
运行结果
开始执行
结束执行
方式三:await()/signal()/signalAll()
可以通过 Condition 类来实现线程之间的协调,可以在 condition 上调用 await()方法使线程进行等待,其他线程调用 signal()或 signalAll()方法唤醒等待的线程 await() 可以指定等待条件, 比 wait()更加灵活 使用 Lock 来获取 Condition 对象
signalAll 通知所有使用了同一个 Condition 对象的线程。signal()通知所有使用了 Condition 对象的某一个线程,通过源码可以看到通知的线程是位于队首的那个。
public class ConditionSychonization {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void beore() {
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 (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
ConditionSychonization sychonization = new ConditionSychonization();
executorService.execute(sychonization::after);
executorService.execute(sychonization::beore);
Thread.sleep(2000);
executorService.shutdown();
}
}
运行结果
before
after