文档章节

java并发编程(2)——wait和notify解析

十二缸帕萨特
 十二缸帕萨特
发布于 2014/04/12 14:04
字数 1106
阅读 598
收藏 7

   JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized()方法类似于操作系统概念中的互斥内存块,在JAVA中的Object类型中,都是带有一个内存锁的,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步、互斥操作。明白这个原理,就能理解为什么synchronized(this)与synchronized(static XXX)的区别了,synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例。如果只是简单的想要实现在JAVA中的线程互斥,明白这些基本就已经够了。但如果需要在线程间相互唤醒的话就需要借助Object.wait(), Object.nofity()了。


wait与notify是java同步机制中重要的组成部分。结合与synchronized关键字使用,可以建立很多优秀的同步模型。
     synchronized(this){}等价与public synchronized void method(){.....}
     同步分为类级别和对象级别,分别对应着类锁和对象锁
类锁是每个类只有一个,如果static的方法被synchronized关键字修饰则在这个方法被执行前必须获得类锁;对象锁类同。(static synchronized是类级别的,非static的synchronized和synchronized块都是对象级别的,即作用在同一new出来的对象上)
     首先,调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(obj){......}的内部才能够去调用obj的wait与notify/notifyAll三个方法,否则就会报错:
     java.lang.IllegalMonitorStateException: current thread not owner
     在调用wait的时候,线程自动释放其占有的对象锁,同时不会去申请对象锁。当线程被唤醒的时候,它才再次获得了去获得对象锁的权利。
     所以,notify与notifyAll没有太多的区别,只是notify仅唤醒一个线程并允许它去获得锁,notifyAll是唤醒所有等待这个对象的线程并允许它们去获得对象锁,只要是在synchronied块中的代码,没有对象锁是寸步难行的。其实唤醒一个线程就是重新允许这个线程去获得对象锁并向下运行。
       顺便说一下notifyall,虽然是对每个wait的对象都调用一次notify,但是这个还是有顺序的,每个对象都保存这一个等待对象链,调用的顺序就是这个链的顺序。其实启动等待对象链中各个线程的也是一个线程,在具体应用的时候,需要注意一下。


应用实例:

建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。这个问题用Object的wait(),notify()就可以很方便的解决。


package cn.com.thread;

/**
 * Description: <交替打印10次ABC>. <br>
 * <p>
 * <使用说明>
 * </p>
 * Makedate:2014-4-12 下午2:14:19
 * 
 * @author gaowenming
 * @version V1.0
 */
public class WaitAndNotifyTest {

	/**
	 * 描述 : <描述函数实现的功能>. <br>
	 * <p>
	 * <使用方法说明>
	 * </p>
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		final PrintABC printAbc = new PrintABC();

		// 循环加载外层
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printA(); // printA
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printB();// printB
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printC();// printC
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

		}

	}

}

/**
 * 
 * 
 * @Description: 交替打印10次ABC
 * @author gaowenming
 * @date 2014-4-12 下午2:17:11
 * 
 */
class PrintABC {
	// 定义全局变量
	boolean a = true;
	boolean b = false;
	boolean c = false;

	public synchronized void printA() throws Exception {
		// 用while,表示一直等待
		while (!a) {
			this.wait();
		}
		System.out.print("A");
		a = false;
		b = true;

		// 执行完后唤醒其他等待的线程
		notifyAll();

	}

	public synchronized void printB() throws Exception {
		while (!b) {
			this.wait();
		}
		System.out.print("B");
		b = false;
		c = true;
		notifyAll();
	}

	public synchronized void printC() throws Exception {
		while (!c) {
			this.wait();
		}
		System.out.println("C");
		c = false;
		a = true;
		notifyAll();
	}
}


运行结果:

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC


© 著作权归作者所有

十二缸帕萨特
粉丝 19
博文 65
码字总数 29186
作品 0
海淀
高级程序员
私信 提问
Java多线程学习(四)等待/通知(wait/notify)机制

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀
2018/04/16
0
0
java中高级大公司多线程面试题

1)在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? lock接口在多线程和并发编...

java成功之路
2018/10/30
0
0
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
493
0
面试系列-并发编程72道面试题及答案

话不多说直接上题,篇幅限制,文末有答案 1.Java中守护线程和本地线程区别 2.线程与进程的区别 3.什么是多线程中的上下文切换 4.死锁与活锁的区别,死锁与饥饿的区别 5.Java中用到的线程调度...

Java邵先生
01/29
0
0
Java并发编程40道面试题及答案——面试稳了

1、线程与进程的区别? 进程是操作系统分配资源的最小单元,线程是操作系统调度的最小单元。 一个程序至少有一个进程,一个进程至少有一个线程。 文末有福利,思维导图和视频资料等你来领 2、...

我最喜欢三大框架
05/27
16
0

没有更多内容

加载失败,请刷新页面

加载更多

移动开发中的 Web:WebView、WebKit、JSCore、Web 优化、热修复、跨平台、Native、Hybrid……

移动开发领域近年来已经逐渐告别了野蛮生长的时期,进入了相对成熟的时代。而一直以来 Native 和 Web 的争论从未停止,通过开发者孜孜不倦的努力,Web 的效率和 Native 的体验也一直在寻求着...

编辑部的故事
3分钟前
0
0
MySQL8.0.17 - Multi-Valued Indexes 简述

本文主要简单介绍下8.0.17新引入的功能multi-valued index, 顾名思义,索引上对于同一个Primary key, 可以建立多个二级索引项,实际上已经对array类型的基础功能做了支持 (感觉官方未来一定...

阿里云官方博客
49分钟前
5
0
make4.1降级 make-3.81、2错误

在编译 make-3.82 的时候出现如下错误提示 glob/glob.c:xxx: undefined reference to `__alloca'` 修改 /glob/glob.c // #if !defined __alloca && !defined __GNU_LIBRARY__ # ifdef __GNUC......

Domineering
50分钟前
11
0
Rainbond集群的安装和运维的原理

本文将解读Rainbond集群的安装和运维的原理,使用户基本了解Rainbond的安装机制和运维重点,便于用户搭建大型Rainbond集群。 1.Rainbond集群节点概述 1.1 节点分类 属性 类型 说明 manage 管...

好雨云帮
今天
9
0
好程序员大数据学习路线分享UDF函数

1.为什么需要UDF? 1)、因为内部函数没法满足需求。 2)、hive它本身就是一个灵活框架,允许用自定义模块功能,如可以自定义UDF、serde、输入输出等。 2.UDF是什么? UDF:user difine fun...

好程序员官方
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部