线程之间的协作
当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调。
join()
在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。
1 public class JoinExample { 2 private class A extends Thread { 3 @Override 4 public void run() { 5 System.out.println("A"); 6 } 7 } 8 9 private class B extends Thread { 10 private A a; 11 B(A a) { 12 this.a = a; 13 } 14 15 @Override 16 public void run() { 17 try { 18 a.join(); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 System.out.println("B"); 23 } 24 } 25 26 public void test() { 27 A a = new A(); 28 B b = new B(a); 29 b.start(); 30 a.start(); 31 } 32 } 33 public static void main(String[] args) { 34 JoinExample example = new JoinExample(); 35 example.test(); 36 }
A
B
wait() notify() notifyAll()
调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify()(随机叫醒一个) 或者 notifyAll() (叫醒所有 wait 线程,争夺时间片的线程只有一个)来唤醒挂起的线程。
它们都属于 Object 的一部分,而不属于 Thread。
只能用在同步方法或者同步控制块中使用!否则会在运行时抛出 IllegalMonitorStateExeception。
使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。
1 public class WaitNotifyExample { 2 public synchronized void before() { 3 System.out.println("before"); 4 notifyAll(); 5 } 6 7 public synchronized void after() { 8 try { 9 wait(); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 System.out.println("after"); 14 } 15 } 16 public static void main(String[] args) { 17 ExecutorService executorService = Executors.newCachedThreadPool(); 18 WaitNotifyExample example = new WaitNotifyExample(); 19 executorService.execute(() -> example.after()); 20 executorService.execute(() -> example.before()); 21 }
before
after
await() signal() signalAll()
java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活。
使用 Lock 来获取一个 Condition 对象。
1 public class AwaitSignalExample { 2 private Lock lock = new ReentrantLock(); 3 private Condition condition = lock.newCondition(); 4 5 public void before() { 6 lock.lock(); 7 try { 8 System.out.println("before"); 9 condition.signalAll(); 10 } finally { 11 lock.unlock(); 12 } 13 } 14 15 public void after() { 16 lock.lock(); 17 try { 18 condition.await(); 19 System.out.println("after"); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } finally { 23 lock.unlock(); 24 } 25 } 26 } 27 public static void main(String[] args) { 28 ExecutorService executorService = Executors.newCachedThreadPool(); 29 AwaitSignalExample example = new AwaitSignalExample(); 30 executorService.execute(() -> example.after()); 31 executorService.execute(() -> example.before()); 32 }
before
after
sleep和wait有什么区别
- sleep 和 wait
- wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
- wait() 会释放锁,sleep() 不会。
- 有什么区别
- sleep() 方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态)。
- wait() 是 Object 类的方法,调用对象的 wait() 方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的 notify() 方法(或 notifyAll() 方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

浙公网安备 33010602011771号