我用了一个可以修改内容的类,StringBuilder,同时使用了新的判断条件.length()==0; public class MyTest { public static void main(String[] args) throws Exception { new TestThread().start(); new TestThread().start(); Thread.sleep(1000); System.out.println("Doing something..."); synchronized (lock) { lock.append(1); // 语句1 lock.notifyAll(); // 语句2 } } static volatile StringBuilder lock = new StringBuilder();; }class TestThread extends Thread { @Override public void run() { synchronized (MyTest.lock) { while (MyTest.lock.length() == 0) { try { MyTest.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getId()); } } }问题难道真的是那个吗?
public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }lock = false; 不会生成新对象,应该是这儿的原因。
应该就是赋值的问题! 查看Object类的源代码,关于notifyAll的说明指向去参考notify的说明,里面说道: This method should only be called by a thread that is the owner of this object's monitor 是对象的monitor有三种方式: * <li>By executing a synchronized instance method of that object. * <li>By executing the body of a <code>synchronized</code> statement * that synchronizes on the object. * <li>For objects of type <code>Class,</code> by executing a * synchronized static method of that class. 这个赋值与Java的对象类型有关,当对一个Boolean赋值为一个boolean型值时,导致原来的lock 所指的对象成为了一个新的boolean的包装类,这样前面的synchronized(lock)就失效了,所以报 除了异常,尝试下面的例子,我们对一个Object调用了一系列的方法来做,lock指向的对象并没有发生 变化,所以synchronized仍然有效,就不会报错了,不过,只是觉得好像是这样,呵呵。 请尝试一下的代码,运行无误public class MyTest { public static void main(String[] args) throws Exception { new TestThread().start(); new TestThread().start(); Thread.sleep(1000); System.out.println("Doing something..."); synchronized (lock) { lock.setIII(2); lock.notifyAll(); } System.exit(0); } static volatile AAA lock = new AAA(1); }class TestThread extends Thread { @Override public void run() { synchronized (MyTest.lock) { while (MyTest.lock.getIII()==1) { try { MyTest.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getId()); } } } class AAA { int iii; public AAA(int i){ iii = i; } public void setIII(int i){ iii = i; } public int getIII(){ return iii; } }
object的notify, notifyall, wait方法必须是被synchronize的,如果一个新对象没有被synchronize的时候调用这些方法就 会current thread not owner。比如楼主问得
我在写一个程序的时候也出现类似问题: 参见http://topic.csdn.net/u/20080710/18/9e9cdcfd-1b8c-4203-b6ba-27a2d8b8b2df.html synchronized (GlobalControl.isEnd) { GlobalControl.isEnd=true; GlobalControl.isEnd.notify(); } 中,GlobalControl.isEnd=true;将使得GlobalControl.isEnd指向一个与 synchronized (GlobalControl.isEnd) 截然不同的对象,当然出问题了。 Exception in thread "pool-1-thread-20" java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method) at thread1.ParaNull.LogicalProcess.run(LogicalProcess.java:367) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907) at java.lang.Thread.run(Thread.java:619) 错误
楼主【tteesstt】截止到2008-07-10 19:39:17的历史汇总数据(不包括此帖):
发帖的总数量:97 发帖的总分数:5700 每贴平均分数:58
回帖的总数量:62 得分贴总数量:5 回帖的得分率:8%
结贴的总数量:97 结贴的总分数:5700
无满意结贴数:0 无满意结贴分:0
未结的帖子数:0 未结的总分数:0
结贴的百分比:100.00% 结分的百分比:100.00%
无满意结贴率:0.00 % 无满意结分率:0.00 %
敬礼!
他那 lock 在 MyTest 中:static volatile Boolean lock = true;
public class MyTest {
public static void main(String[] args) throws Exception {
new TestThread().start();
new TestThread().start();
Thread.sleep(1000);
System.out.println("Doing something...");
synchronized (lock) {
lock.notifyAll();
lock.wait();
condition = true; // 语句1
lock.notifyAll(); // 语句2
}
System.exit(0);
} static volatile Object lock = new Object(); static volatile Boolean condition = false;;
}class TestThread extends Thread {
@Override
public void run() {
synchronized (MyTest.lock) {
while (!MyTest.condition) {
try {
MyTest.lock.wait();
System.out.println(getId());
MyTest.lock.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getId());
}
}
}不过我也不清楚为何条件和锁用一个对象为何不行?难道???????那个赋值的问题,lock = false; // 语句1重新生成了一个新的对象吗???造成锁异常我去测试看看!!
public class MyTest {
public static void main(String[] args) throws Exception {
new TestThread().start();
new TestThread().start();
Thread.sleep(1000);
System.out.println("Doing something...");
synchronized (lock) {
lock.append(1); // 语句1
lock.notifyAll(); // 语句2
}
} static volatile StringBuilder lock = new StringBuilder();;
}class TestThread extends Thread {
@Override
public void run() {
synchronized (MyTest.lock) {
while (MyTest.lock.length() == 0) {
try {
MyTest.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getId());
}
}
}问题难道真的是那个吗?
public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}lock = false; 不会生成新对象,应该是这儿的原因。
lock.notifyAll(); //再通知也没用
查看Object类的源代码,关于notifyAll的说明指向去参考notify的说明,里面说道:
This method should only be called by a thread that is the owner of this object's monitor
是对象的monitor有三种方式:
* <li>By executing a synchronized instance method of that object.
* <li>By executing the body of a <code>synchronized</code> statement
* that synchronizes on the object.
* <li>For objects of type <code>Class,</code> by executing a
* synchronized static method of that class.
这个赋值与Java的对象类型有关,当对一个Boolean赋值为一个boolean型值时,导致原来的lock
所指的对象成为了一个新的boolean的包装类,这样前面的synchronized(lock)就失效了,所以报
除了异常,尝试下面的例子,我们对一个Object调用了一系列的方法来做,lock指向的对象并没有发生
变化,所以synchronized仍然有效,就不会报错了,不过,只是觉得好像是这样,呵呵。
请尝试一下的代码,运行无误public class MyTest {
public static void main(String[] args) throws Exception {
new TestThread().start();
new TestThread().start();
Thread.sleep(1000);
System.out.println("Doing something...");
synchronized (lock) {
lock.setIII(2);
lock.notifyAll();
}
System.exit(0);
} static volatile AAA lock = new AAA(1);
}class TestThread extends Thread {
@Override
public void run() {
synchronized (MyTest.lock) {
while (MyTest.lock.getIII()==1) {
try {
MyTest.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getId());
}
}
}
class AAA {
int iii;
public AAA(int i){
iii = i;
}
public void setIII(int i){
iii = i;
}
public int getIII(){
return iii;
}
}
看源码,不会创建新 Boolean 对象。
lock.notifyAll(); //再通知也没用
所以就抛出了 IllegalMonitorStateException 的异常。只要把改变值之前的 lock 引用对象再赋给一个临时的变量,由
这个临时变量来通知就行了,呵呵。 synchronized (lock) {
Boolean b = lock;
lock = false;
b.notifyAll();
}
true的 Boolean 对象监视范围内并没有进行等待的线程,改为:值为 false 的 Boolean 对象监视范围内并没有进行等待的线程,lock = false;
Boolean.TRUE.notifyAll();
}
那么到底有没有两个Boolean对象呢?
我认为值为true和值为false的Boolean对象分别拥有自己的Monitor(监视器),所以正如火龙果前辈说的,为false的Boolean对象监视器替换掉true的监视器之后,无法退出sychronized块,因为曾经读过JVM官方规范:每次进入sychronized块监视器计数要加1,退出的时候要减1,如果最终为0才能正常退出,否则抛出MonitorState异常。而当初进入sychronized加1的是true的Boolean对象的监视器,退出的时候计数减1的却是为false的Boolean的监视器
lock = false;
lock.notifyAll();
}
所有的封装类都是只读的,所以 lock = false; 将返回一个新的对象,而当前线程获得的是原对象的锁,
所以在新的lock对象上调用notifyAll导致IllegalMonitorStateException,与另外两个线程无关,
如果一个线程没有获得某个对象的锁而调用它的notifyAll将导致IllegalMonitorStateException。
个人理解,望指证。
更正,还是会出现异常,原因,对象不同.控制台输出赋值前后的 hashcode 为:Doing something...
1231
1237
lock已经同步 这个volatile不用加吧
lock.notifyAll(); // 语句2
这种情况下,必然出错阿lock已经是一个新对象了,而lock.notifyAll()在新对象上没有被同步。所以current thread not owner。
换个顺序以后,在原来对象上notifyAll()了lock才变成新对象,所以没有错了
会current thread not owner。比如楼主问得
参见http://topic.csdn.net/u/20080710/18/9e9cdcfd-1b8c-4203-b6ba-27a2d8b8b2df.html
synchronized (GlobalControl.isEnd) {
GlobalControl.isEnd=true;
GlobalControl.isEnd.notify();
} 中,GlobalControl.isEnd=true;将使得GlobalControl.isEnd指向一个与
synchronized (GlobalControl.isEnd) 截然不同的对象,当然出问题了。
Exception in thread "pool-1-thread-20" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at thread1.ParaNull.LogicalProcess.run(LogicalProcess.java:367)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)
错误
会产生中断异常
当lock要成为boolean时,是要申明成look=new Boolean(Boolean.FALSE);
不要重新分配被锁定对象的对象引用
developerWorks
Peter Haggar, 高级软件工程师, IBM2000 年 10 月 01 日 编者按:编者按:本文是从“Practical Java”( Addison-Wesley 出版)一书节选而来的。您可以从 Borders.com 订购该书。请阅读我们对作者 Peter Haggar 的 采访。synchronized 关键字锁定对象。对象是在 synchronized 代码内部被锁定的,这一点对此对象以及您对其对象引用所作的更改意味着什么呢?对一个对象作同步处理只锁定该对象。但是,必须注意不要重新分配被锁定对象的对象引用。那么如果这样做会发生什么情况呢?请考虑下面这段代码,它实现了一个 Stack:class Stack
{
private int StackSize = 10;
private int[] intArr = new int[stackSize];
private int index; //Stack 中的下一个可用位置。
public void push(int val)
{
synchronized(intArr) {
//如果已满,则重新分配整数数组(即我们的 Stack)。
if (index == intArr.length)
{
stackSize *= 2;
int[] newintArr == new int[stackSize];
System.arraycopy(intArr, 0, newintArr, 0, intArr.length);
intArr = newintArr;
}
intArr[index] == val;
index++;
}
}
public int pop()
{
int retval;
synchronized(intArr) {
if (index > 0)
{
retval = intArr[index-1]; //检索值,
index--; //并使 Stack 减少 1 个值。
return retval;
}
}
throw new EmptyStackException();
}
//...
}
这段代码用数组实现了一个 Stack。创建了一个初始大小为 10 的数组来容纳整数值。此类实现了 push 和 pop 方法来模拟 Stack 的使用。在 push 方法中,如果数组中没有更多的空间来容纳压入的值,则数组被重新分配以创建更多的存储空间。(故意没有用 Vector 来实现这个类。 Vector 中不能储存基本类型。)请注意,这段代码是要由多个线程进行访问的。push 和 pop 方法每次对该类的共享实例数据的访问都是在 synchronized 块内完成的。这样就保证了多个线程不能并发访问此数组而生成不正确的结果。这段代码有一个主要的缺点。它对整数数组对象作了同步处理,而这个数组被 Stack 类的 intArr 所引用。当 push 方法重新分配此整数数组时,这个缺点就会显露出来。当这种情况发生时,对象引用 intArr 被重新指定为引用一个新的、更大的整数数组对象。请注意,这是在 push 方法的 synchronized 块执行期间发生的。此块针对 intArr 变量引用的对象进行了同步处理。因此,在这段代码内锁定的对象不再被使用。请考虑以下的事件序列: 1. 线程 1 调用 push 方法并获得 intArr 对象的锁。 2. 线程 1 被线程 2 抢先。 3. 线程 2 调用 pop 方法。此方法因试图获取当前线程 1 在 push 方法中持有的同一个锁而阻塞。 4. 线程 1 重新获得控制并重新分配数组。 intArr 变量现在引用一个不同的变量。 5. push 方法退出并释放它对原来的 intArr 对象的锁。 6. 线程 1 再次调用 push 方法并获得新 intArr 对象的锁。 7. 线程 1 被线程 2 抢先。 8. 线程 2 获得旧 intArr 对象的对象锁并试图访问其内存。现在线程 1 持有由 intArr 引用的新对象的锁,线程 2 持有由 intArr 引用的旧对象的锁。因为两个线程持有不同的锁,所以它们可以并发执行 synchronized push 和 pop 方法,从而导致错误。很明显,这不是所希望的结果。这个问题是因 push 方法重新分配被锁定对象的对象引用而造成的。当某个对象被锁定时,其他线程可能在同一个对象锁上被阻塞。如果将被锁定对象的对象引用重新分配给另一个对象,其他线程的挂起锁则是针对代码中已不再相关的对象的。您可以这样修正这段代码,去掉对 intArr 变量的同步,而对 push 和 pop 方法进行同步。通过将 synchronized 关键字添加为方法修饰符即可实现这一点。正确的代码如下所示:class Stack
{
//与前面相同...
public synchronized void push(int val)
{
//如果为空,则重新分配整数数组(即我们的 Stack)。
if (index == intArr.length)
{
stackSize *= 2;
int[] newintArr = new int[stackSize];
System.arraycopy(intArr, 0, newintArr, 0, intArr.length);
intArr = newintArr;
}
intArr[index]= val;
index++;
}
public synchronized int pop()
{
int retval;
if (index > 0)
{
retval = intArr[index-1];
index--;
return retval;
}
throw new EmptyStackException();
}
}
这个修改更改了实际上获取的锁。获取的锁是针对为其调用方法的对象的,而不是锁定 intArr 变量所引用的对象。因为获取的锁不再针对 intArr 所引用的对象,所以允许代码重新指定 intArr 对象引用。
关于作者 Peter Haggar 是 IBM 的高级软件工程师。他目前正在研究新兴的 Java 和因特网技术,并且是 IBM 实时 Java 参考实现的项目主持人。他有丰富的编程经验,从事过开发工具、类库和操作系统等方面的工作。在许多行业研讨会上,他也经常就 Java 和其他技术作技术性发言。他于 1987 年在纽约获得 Clarkson 大学计算机科学学士学位。可以通过 [email protected] 与他联系