返回信息流首先LZ写了一个轮流打出1,2的程序没问题,然后写一个轮流执行i++的程序出错了,觉得两个程序写的思路一样啊,但是第二个抛出java.lang.IllegalMonitorStateException 求高人指出错在哪里了
----------------------------------------------
经高人指点,是由于integer之后i++,Integer变成了另外一个对象,不能持有锁,所以会抛出异常。
InTurn.java(轮流打出1 2,抄的网上的)执行没有问题
public class InTurn implements Runnable{
private Object obj=new Object();
private int num;
public InTurn(Object obj, int num){
this.obj=obj;
this.num=num;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
while(true){
synchronized (obj) {
obj.notifyAll();
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
}
public static void main(String args[]){
Object obj=new Object();
Thread a=new Thread(new InTurn(obj,1));
Thread b=new Thread(new InTurn(obj,2));
a.start();
b.start();
}
}
Increase.java(想让两个线程轮流执行i++,抛出异常了)
public class Increase implements Runnable{
private Integer i;
public Increase(Integer i){
this.i=i;
}
public static void main(String args[]) {
Integer i=new Integer(0);
Thread a=new Thread(new Increase(i));
Thread b=new Thread(new Increase(i));
a.start();
b.start();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
while (true) {
synchronized (i) {
i.notifyAll();
i++;
System.out.println(Thread.currentThread().getName() + " " + i);
try {
i.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
这是一条镜像帖。来源:北邮人论坛 / java / #40374同步于 2015/5/1
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
[问题]关于两线程交替执行的问题(已解决)
homeless271
2015/5/1镜像同步7 回复
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
把Integer换成AtomicInteger试试?
【 在 homeless271 的大作中提到: 】
: 首先LZ写了一个轮流打出1,2的程序没问题,然后写一个轮流执行i++的程序出错了,觉得两个程序写的思路一样啊,但是第二个抛出java.lang.IllegalMonitorStateException 求高人指出错在哪里了
: InTurn.java(轮流打出1 2,抄的网上的)执行没有问题
: public class InTurn implements Runnable{
: ...................
我擦,好牛,换成atomicInteger就可以了,这是为什么??
i++在synchronized (i)里,可以保证只有一个线程修改i的
求原理
【 在 aiquestion 的大作中提到: 】
: 把Integer换成AtomicInteger试试?
额。。好像不是AtomicInteger的问题。
感觉应该是因为Integer本身是不可变的。
所以i++应该是把i指向的Integer对象换了一个。
你新加一个private static Object lock = new Object();
来做同步的锁也是可以得。
你可以随便写个程序debug一下
Integer i = new Integer(0);
i++;//这个之后i指向的是另一个对象
【 在 homeless271 的大作中提到: 】
: 我擦,好牛,换成atomicInteger就可以了,这是为什么??
: i++在synchronized (i)里,可以保证只有一个线程修改i的
: 求原理
: ...................
果真是这个问题,好腻害啊
【 在 aiquestion 的大作中提到: 】
: 额。。好像不是AtomicInteger的问题。
: 感觉应该是因为Integer本身是不可变的。
: 所以i++应该是把i指向的Integer对象换了一个。
: ...................
Integer是不可变的对象。你不能改变一个integer对象的值。
另外这个程序(包括从网上抄来的那个)有问题:wait和notify的用法。wait可以没有理由地醒来(spurious wakeup),所以必须在一个循环里等待。而且正因为wait不可靠,必须用一个变量来确定你要等的事情到底发生了没有。
package cn.byr.nuanyangyang.turn;
class SharedState {
public int num = 0; // 我们真正要改的是SharedState变量的域,而不是那个不可变的Integer对象。
public int whoseTurn = 0; // 这个用来指示现在应该谁运行
}
class Incrementer implements Runnable {
private SharedState state;
private int myID;
private int friendID;
public Incrementer(SharedState state, int myID, int friendID) {
this.state = state;
this.myID = myID;
this.friendID = friendID;
}
@Override
public void run() {
try {
synchronized (state) {
while (true) {
while (state.whoseTurn != myID) { // 因为wait可以随便醒来,所以必须用循环等,直到state.whoseTurn == myID为止
state.wait(); // wait的时候自动解锁,所以外层的while放在synchronized里面也没关系
}
int curNum = state.num; // 反正我们有锁,不需要原子内存操作,所以不需要volatile也不需要AtomicInteger
int newNum = curNum + 1;
System.out.format("[%d] num = %d, changing to %d\n", myID, curNum, newNum);
state.num = newNum;
state.whoseTurn = friendID;
state.notifyAll();
}
}
} catch (InterruptedException e) { // 这是唯一的出口。wait的时候如果被interrupt,就会抛出异常。
System.out.format("[%d] Interrupted. Stop now.\n", myID);
}
}
}
public class InTurn {
public static void main(String[] args) throws InterruptedException {
SharedState state = new SharedState();
Thread t1 = new Thread(new Incrementer(state, 1, 2));
Thread t2 = new Thread(new Incrementer(state, 2, 1));
state.whoseTurn = 1;
t1.start();
t2.start();
Thread.sleep(1000);
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
}
}
报错因为你锁没拿对,你自增以后i就不是原来的i了,而且用这个Integer当锁的话,真心不知道会怎么处理装箱拆箱,在加上Integer又是Immutable的。。。
暖神,interrupt之后是不是不需要join了?
【 在 nuanyangyang 的大作中提到: 】
: Integer是不可变的对象。你不能改变一个integer对象的值。
: 另外这个程序(包括从网上抄来的那个)有问题:wait和notify的用法。wait可以没有理由地醒来(spurious wakeup),所以必须在一个循环里等待。而且正因为wait不可靠,必须用一个变量来确定你要等的事情到底发生了没有。
: [code=java]
: ...................