多线程同步中 syschronized 锁问题

之前看过张孝闲讲线程中的一个实例,让主线程运行10次,然后子线程再运行20次,这样循环50次。今天自己闲着写了一下,刚写出的代码报了个java.lang.IllegalMonitorStateException的错误,网上查了一下,发现了问题是锁的问题,于是自己总结了一下。

先说一点最重要的:syschronized同步的基础必须是多个线程拥有同一个锁(对象锁,变量锁),不能没有锁权限,也不能是拥有不同锁的权限。下面请看实例。

先贴第一版的错误代码:

public class ThreadNotity {
	/**
	 *
	 * @param args
	 *
	 * @deprecated 线程1执行10次,线程2执行20次,循环50次
	 */

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final A a = new A();
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				for (int i = 0; i < 50; i++) {
					a.printA();
				}
			}

		}).start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for (int i = 0; i < 50; i++) {
					a.printB();
				}
			}

		}).start();
	}
}

class A {

	private boolean isArun = true;
	private static Object lock = new Object();

	public synchronized void printA() {
		while (!isArun) {
			try {
				A.class.wait();
			//	lock.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 10; i++)
			System.out.println(Thread.currentThread().getName() + "  i=" + i);
		isArun = false;
		A.class.notifyAll();
	//	lock.notifyAll();
	}

	public synchronized void printB() {
		while (isArun) {
			try {
				A.class.wait();
	  		//  lock.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 20; i++)
			System.out.println(Thread.currentThread().getName() + "  i=" + i);
		isArun = true;
		A.class.notifyAll();
		lock.notifyAll();

	}

}

这个程序不管用A.class.wait()还是lock.wait()都会报java.lang.IllegalMonitorStateException错误,百度一下java.lang.IllegalMonitorStateException  API中解释为:抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。可以理解为,正在运行的线程并没有获得指定的对象锁(上述程序中具体指
class A和Object lock).

于是根据synchronized一般的定义方法,又写了几种解决方案。

1.synchronized 修改方法,

先尝试不加对象,直接调用wait(),notity()方法,程序可以运行成功;接着尝试用了this,this.wait(),this.notity(),程序运行成功。然后就在想这个this到底在指什么。显然,并不是A.class
和 lock.我们知道this一般是指向调用这个方法的对象,在本程序中,调用方法的对象是a,于是就将a作为方法的参数,传递进去,并选择synchronized 的对象锁为a,调用a.wait(),a.notityAll(),程序可以运行成功;然后又将a和this混用,依然可以运行成功。显然此处当用synchronized
修饰方法时,synchronized 获得的对象锁是调用此方法的对象的对象锁,即a,这里也可用this代替。

class A {  

    private boolean isArun = true;
    private static Object lock = new Object();
    //<span style="font-family: monospace; font-size: 13px; line-height: 19.2000007629395px; white-space: pre;">synchronized 修改方法</span>
	public synchronized void printA(A a) {
		while (!isArun) {
			try {
				wait();
			//	this.wait();
			//	a.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 10; i++)
			System.out.println(Thread.currentThread().getName() + "  i=" + i);
		isArun = false;
		notifyAll();
	//	this.notifyAll();
	//	a.notifyAll();
	}

	public synchronized void printB(A a) {
		while (isArun) {
			try {
				wait();
				//	this.wait();
				//	a.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 20; i++)
			System.out.println(Thread.currentThread().getName() + "  i=" + i);
		isArun = true;
		notifyAll();
	//	this.notifyAll();
	//	a.notifyAll();

	}

}   

2.  synchronized 去修饰代码片段

synchronized 修饰代码片段时,锁可以自己指定,可以为对象lock,也可以为变量,或者是类的字节码
A.class。但是必须相同。

class A {

	private boolean isArun = true;
	private static Object lock = new Object();

	public  void printA(A a) {
		synchronized (lock) {
			while (!isArun) {
				try {
					//A.class.wait();
					 lock.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for (int i = 0; i < 10; i++)
				System.out.println(Thread.currentThread().getName() + "  i="
						+ i);
			isArun = false;
			 lock.notifyAll();
			 //A.class.notifyAll();
		}
	}

	public  void printB(A a) {
		synchronized (lock) {
			while (isArun) {
				try {
					//A.class.wait();
					 lock.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for (int i = 0; i < 20; i++)
				System.out.println(Thread.currentThread().getName() + "  i="
						+ i);
			isArun = true;
			 lock.notifyAll();
			 //A.class.notifyAll(); 

		}
	}

}
时间: 2024-10-04 04:53:53

多线程同步中 syschronized 锁问题的相关文章

21、Java并发性和多线程-Java中的锁

以下内容转自http://ifeve.com/locks/: 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂.因为锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,所以我们还不能完全摆脱synchronized关键字(译者注:这说的是Java 5之前的情况). 自Java 5开始,java.util.concurrent.locks包中包含了一些锁的实现,因此你不用去实现自己的锁了.但是你仍然需要去

win32进阶必备:多线程同步之互斥锁

应用多线程互斥锁之前首先简单过一下C程序可能用到的3个创建线程函数: CreateThread,windows系统提供的唯一创建线程API,_beginthread和_beginthreadex都在内部调用了CreateThread,直接调用该函数创建多线程的C程序存在内存泄露的可能性,通常不推荐直接使用,创建多线程应用程序时以_beginthreadex替代,详细原因下面讲解. _beginthread,最初版的C运行时库多线程创建函数,参数过少,存在一些天然的缺陷,无法创建具有运行安全属性的

Java 多线程, 同步访问, 线程锁,锁对象,ReentrantLock,synchronized

1.为什么要同步访问数据? 当两个或以上的线程需要共享对同一数据的存取,可能会发生共享数据的讹误. 2.实现同步的方式 2.1 ReentrantLock类 School类: class School{ private int stuNum; private Lock lock; private Condition condition; public School(int stuNum) { this.stuNum = stuNum; lock = new ReentrantLock(); co

Objective-C中的锁及应用-13- 多线程

Objective-C中的锁及应用 在多线程编程中,锁是非常重要的工具,而Objective-C提供了好几种不同类型的锁,下面就来看一下这些锁都是怎么用的. 0. POSIX Mutex Lock Mutex lock也就是互斥锁,是Unix/Linux平台上提供的一套同步机制.互斥锁提供了三个函数,从函数名就可以知道他们的作用: int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_m

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是class对象 我们在上节验证了同步函数的锁是this,但是对于静态同步函数,你又知道多少呢? 我们做一个这样的小实验,我们给show方法加上static关键字去修饰 private static synchronized void show() { if (tick > 0) { try { Thread

c#语言-多线程中的锁系统

介绍 平常在多线程开发中,总避免不了线程同步.这次就对net多线程中的锁系统做个简单描述. 目录 一:lock.Monitor 1:基础. 2: 作用域. 3:字符串锁. 二: mutex 三:Semaphore 四:总结 一:lock.Monitor 1:基础 Lock是Monitor语法糖简化写法.Lock在IL会生成Monitor. //======Example 1===== string obj = "helloworld"; lock (obj) { Console.Wri

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

Java多线程---同步与锁

一,线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 二.同步和锁定 1.锁的原理 Java中每个对象都有一个内置锁. 当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁定对象.在对象上锁定或在对象上同步. 当程序运行到synchronized同步方法或代码块时该对象锁才起作用. 一个对象只有一个锁.所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回

C#中的多线程 - 同步基础

原文:http://www.albahari.com/threading/part2.aspx 1同步概要 在第 1 部分:基础知识中,我们描述了如何在线程上启动任务.配置线程以及双向传递数据.同时也说明了局部变量对于线程来说是私有的,以及引用是如何在线程之间共享,允许其通过公共字段进行通信. 下一步是同步(synchronization):为期望的结果协调线程的行为.当多个线程访问同一个数据时,同步尤其重要,但是这是一件非常容易搞砸的事情. 同步构造可以分为以下四类: 简单的阻塞方法 这些方法