
public class DeadLock { private Integer a = 0; private Integer b = 0; private void createDeadLock() { Runnable first = () -> { for (int i = 0; i < 100000; i++) { synchronized(this.a) { System.out.println("锁住 a"); this.a++; synchronized(this.b) { this.b++; } System.out.println("对 a、b 的处理完成:" + a + " " + b); } } }; Runnable secOnd= () -> { for (int i = 0; i < 100000; i++) { synchronized(this.b) { System.out.println("锁住 b"); this.b++; synchronized(this.a) { this.a++; } System.out.println("对 a、b 的处理完成:" + a + " " + b); } } }; Thread firstThread = new Thread(first); Thread secOndThread= new Thread(second); firstThread.start(); secondThread.start(); } public static void main(String[] args) { DeadLock deadLock = new DeadLock(); deadLock.createDeadLock(); } } 1 hjchjc1993 OP 本来想搞一个死锁出来,运行了多次,结果是死锁没有出现,反而 a 和 b 的值表示这么做是线程不安全的,求教啊,别沉 |
2 hjchjc1993 OP 再顶下~ |
3 gaius 2019-03-06 14:41:42 +08:00 输出语句没同步 |
4 geelaw 2019-03-06 14:48:04 +08:00 Integer 对象是不可变对象,假设 x 是一个 Integer,则 x++ 等同于 x = new Integer(x.intValue() + 1),但是你锁住的对象是之前的对象,是 x 引用了谁改变了,而不是 x 引用的那个谁改变了。 |
5 syncnano 2019-03-06 14:53:42 +08:00 ++不是原子操作外加对象引用其实变了,所以没有锁住吧? |
6 ipwx 2019-03-06 1:55:06 +08:00 你把两条 System.out.println 语句输出的内容做一下细微变化再看看。 |
7 hjchjc1993 OP @geelaw synchronized 貌似只能锁对象,那这种情况该怎么修改代码才能线程安全呢? |
8 gaius 2019-03-06 15:37:02 +08:00 首先 Integer a =0; Integer b=0;是同一个对象,一把锁。synchronized 里的对象改变之后,原对象的锁就释放了。 其实你锁的是数字。 |
9 hjchjc1993 OP @gaius 确实应该是没锁住,对 JVM 的内存模型还是不太清楚啊。 |
10 ihavecat 2019-03-06 16:00:06 +08:00 Integer -128 到 127 是放在缓存里的,你这种写法和 a 和 b 是指向同一地址的 |
11 hjchjc1993 OP @ihavecat 改为了 private Integer a = new Integer(200); private Integer b = new Integer(200); 最后的结果显示仍然不是线程安全的 |
12 Malthael 2019-03-06 16:35:11 +08:00 把 b 改个对象,比如说 Double,锁对象时用 synchronized (Integer.class)和 synchronized (Double.class) |
13 Yuicon 2019-03-06 16:39:01 +08:00 @hjchjc1993 写个包装类 |
14 hjchjc1993 OP @Malthael 其实用其它的写法是很容易做到线程安全的,我只是对这种写法上锁失败的原因表示好奇。。 |
15 ihavecat 2019-03-06 16:48:07 +08:00 synchronized 中锁住的对象不能被改变,在循环体内进行++操作后,对象变了,各自没锁住,就没法死锁了,建议用字符串或者 AtomicInteger 试试 @hjchjc1993 |
16 brainfxxk 2019-03-06 16:58:13 +08:00 Integer 类的问题 你把锁换成 private final Object 累加的数值分别加到一个 int/Integer 字段上 再试试 |
17 hjchjc1993 OP 这样写就没问题了。原来的问题可能确实出现在没有锁 final 对象,自增改变了对象,所以没锁住。 下面这么样写就死锁了。。。 public class DeadLockProblem { private final Counter counter1 = new Counter(); private final Counter counter2 = new Counter(); private void createDeadLock() { Runnable first = () -> { for (int i = 0; i < 100000; i++) { synchronized(counter1) { System.out.println("锁住 counter1"); counter1.addOne(); synchronized(counter2) { counter2.addOne(); } System.out.println("对 counter1、counter2 的处理完成:" + counter1.getCount() + " " + counter2.getCount()); } } }; Runnable secOnd= () -> { for (int i = 0; i < 100000; i++) { synchronized(counter2) { System.out.println("锁住 counter2"); counter2.addOne(); synchronized(counter1) { counter1.addOne(); } System.out.println("对 counter1、counter2 的处理完成:" + counter1.getCount() + " " + counter2.getCount()); } } }; Thread firstThread = new Thread(first); Thread secOndThread= new Thread(second); firstThread.start(); secondThread.start(); } public static void main(String[] args) { DeadLockProblem deadLock = new DeadLockProblem(); deadLock.createDeadLock(); } } class Counter { private int count = 0; void addOne() { count++; } int getCount() { return count; } } |
18 hjchjc1993 OP @brainfxxk 谢谢 正解 |
19 MachineSpirit 2019-03-06 18:40:51 +08:00 via Android 我一直以为 synchronized 锁的是对象的引用。想了想只锁引用也确实不安全。应该是对象和引用都被锁了吧? |