Concurrency Item - 用并发工具替换wait和notify

标题起得有些奇怪,好端端的为什么要替换wait和notify?

在论坛看到了这么一段:

14. 为什么wait(), notify()和notifyAll()必须在同步方法或者同步块中被调用?
当一个线程需要调用对象的wait()方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的notify()方法。同样的,当一个线程需要调用对象的notify()方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。

但这并不是Java语义上的限制,即便写成如下这种形式(摘自爆栈某人提问:wait/notify这玩意儿到底怎么用?),编译仍然会通过无误:

public void waiting() {
	for (int i = 0; i < 10; i++) {
		if (i == 5)
			try {
				this.wait();
			} catch (InterruptedException e) {

        		}
                else
	        	System.out.println(i);
	}
	System.out.println("notify me now");
	this.notify();
}

我不认为会有人在调用某个方法时总是先确认一下javadoc....我认为从IDE列出来的方法提示里选择一个像那么回事的方法执行一遍再确认文档比较符合正常人的习惯。

有人提出这样的问题也说明了一个问题:wait/notify用起来确实很晦涩。

如果觉得还不够晦涩,认为"只要在synchronized块里面用就可以了",其实并不是这样,参考javadoc中的一段:

A thread can also wake up without being notified, interrupted, or

timing out, a so-called spurious wakeup.  While this will rarely

occur in practice, applications must guard against it by testing for

the condition that should have caused the thread to be awakened, and

continuing to wait if the condition is not satisfied.  In other words,

waits should always occur in loops, like this one:

synchronized (obj) {
    while (<condition does not hold>)
        obj.wait(timeout);
        // ... Perform action appropriate to condition
}

下面是一个线程莫名苏醒的情况:

  1. 在某个线程调用notify后和等待线程苏醒的这段时间之内另一个线程得到了锁并改变了受保护的状态。
  2. 其他线程恶意(也就是破坏可变性条件)调用notify或者直接notifyAll.
  3. 伪唤醒 (http://en.wikipedia.org/wiki/Spurious_wakeup).

自Java 1.5发行,JDK提供了更高级的并发工具,这些工具可以更优雅地解决以往只有wait+notify才能解决的问题。

所谓“更高级的并发工具”包括三类:

  1. Executor Framework
  2. 并发集合
  3. 同步器 (Latch,Barrier,Semaphor什么的...)

对于新代码,如今几乎很少有需要使用wait/notify的情况。

如果必须使用wait/notify,则需要保证是在循环里调用wait,尽管这感觉很蠢。

而为了防止活跃性问题,还是多加利用Java 5之后的各种工具吧。

时间: 2024-10-18 12:43:46

Concurrency Item - 用并发工具替换wait和notify的相关文章

并发工具类(二)同步屏障CyclicBarrier

前言 ??JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Phaser: ??CountDownLatch.CyclicBarrier.Semphore.Phaser 这四个工具类提供一种并发流程的控制手段:而Exchanger工具类则提供了在线程之间交换数据的一种手段. 简介 ??CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Ba

并发工具类

问题:Thread.join的代码如下,为什么没有加锁却可以wait?另外下面的代码说明线程结束的时候会signal正在wait的线程,实际是signalAll(). while(isAlive()){ wait(0); } 并发工具类(提供超时等重载方法,含有查询线程排队和统计的接口) 1.CountDownLatch 1.不能重复使用 2.相当于Thread.join() 3.调用countdown方法happens-before,另外一个线程调用await方法. 2.CyclicBarri

JavaEE Tutorials (27) - Java EE的并发工具

27.1并发基础427 27.1.1线程和进程42827.2并发工具的主要组件42827.3并发和事务42927.4并发和安全43027.5jobs并发示例430 27.5.1运行jobs示例43027.6taskcreator并发示例433 27.6.1运行taskcreator示例43527.7关于并发工具的更多信息436

并发工具类:CountDownLatch、CyclicBarrier、Semaphore

在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch 1 import java.util.concurrent.CountDownLatch; 2 3 4 public class CountDownLatchTest 5 { //设置N为2 6 static CountDownLatch c = new CountDownLatch(2); 7 p

Java并发工具类 - CountDownLatch

Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html 官方API. CountDownLatch能够使一个或多个线程等待其他线程完成各自的工作后再执行:CountDownLatch是JDK 5+里面

Java并发工具类CyclicBarrier

CyclicBarrier同步屏障 java并发工具类中有一个叫做CyclicBarrier的类,与CountDownLatch类似,都可以实现线程间的同步,但是差别是CyclicBarrier是可重置的同步屏障. 想象一个场景,有N个人不同时间走到一扇门,因为门需要N个人合力才能推开,所以人不足N个时,只能阻塞在此,等到N个人都到了之后,可以推开门,继续进行之前的工作.CyclicBarrier就是这扇门. 看看下面的代码,定义了一个线程数为2的,CyclicBarrier,并在主线程和另外一

JDK并发工具类

在JDK的并发包里提供了几个非常有用的并发工具类.CountDownLatch.CyclicBarrier和Semaphore工具类提供了一种并发流程控制的手段,Exchanger工具类则提供了在线程间交换数据的一种手段. 1等待多线程完成的CountDownLatch CountDownLatch:CountDownLatch允许一个或多个线程等待其他线程完成操作.与thread.join方法类似但功能更多.该计数器只能使用一次 CountDownLatch的构造函数接收一个int类型的参数作

Java线程与并发编程实践----并发工具类与Executor框架

java5之前,我们使用诸如synchronized,wait(),notify()方法对线程的操作属于对 底层线程的操作,这样会出现很多的问题: 低级的并发原语,比如synchronized,wait(),notify()经常难以正确使用.误用会导致 竞态条件,线程饿死,死锁等风险. 泰国依赖synchronized会影响程序性能以及程序的可扩展性 开发者经常需要高级线程结构,如线程池,信号量.java对底层线程的操作不包含这些结. 为解决这些问题,java5引入并发工具类,该工具类主要有下面

Java学习笔记—多线程(并发工具类,java.util.concurrent.atomic包)

在JDK的并发包里提供了几个非常有用的并发工具类.CountDownLatch.CyclicBarrier和Semaphore工具类提供了一种并发流程控制的手段,Exchanger工具类则提供了在线程间交换数据的一种手段.本章会配合一些应用场景来介绍如何使用这些工具类. CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作.假如有这样一个需求:我们需要解析一个Excel里多个sheet的数据,此时可以考虑使用多线程,每个线程解析一个sheet里的数据,