BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #40374同步于 2015/5/1
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

[问题]关于两线程交替执行的问题(已解决)

homeless271
2015/5/1镜像同步7 回复
首先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(); } } } } }
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
aiquestion机器人#1 · 2015/5/1
把Integer换成AtomicInteger试试? 【 在 homeless271 的大作中提到: 】 : 首先LZ写了一个轮流打出1,2的程序没问题,然后写一个轮流执行i++的程序出错了,觉得两个程序写的思路一样啊,但是第二个抛出java.lang.IllegalMonitorStateException 求高人指出错在哪里了 : InTurn.java(轮流打出1 2,抄的网上的)执行没有问题 : public class InTurn implements Runnable{ : ...................
homeless271机器人#2 · 2015/5/1
我擦,好牛,换成atomicInteger就可以了,这是为什么?? i++在synchronized (i)里,可以保证只有一个线程修改i的 求原理 【 在 aiquestion 的大作中提到: 】 : 把Integer换成AtomicInteger试试?
aiquestion机器人#3 · 2015/5/1
额。。好像不是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的 : 求原理 : ...................
homeless271机器人#4 · 2015/5/1
果真是这个问题,好腻害啊 【 在 aiquestion 的大作中提到: 】 : 额。。好像不是AtomicInteger的问题。 : 感觉应该是因为Integer本身是不可变的。 : 所以i++应该是把i指向的Integer对象换了一个。 : ...................
nuanyangyang机器人#5 · 2015/5/1
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(); } }
yyy8848机器人#6 · 2015/5/1
报错因为你锁没拿对,你自增以后i就不是原来的i了,而且用这个Integer当锁的话,真心不知道会怎么处理装箱拆箱,在加上Integer又是Immutable的。。。
yyy8848机器人#7 · 2015/5/1
暖神,interrupt之后是不是不需要join了? 【 在 nuanyangyang 的大作中提到: 】 : Integer是不可变的对象。你不能改变一个integer对象的值。 : 另外这个程序(包括从网上抄来的那个)有问题:wait和notify的用法。wait可以没有理由地醒来(spurious wakeup),所以必须在一个循环里等待。而且正因为wait不可靠,必须用一个变量来确定你要等的事情到底发生了没有。 : [code=java] : ...................