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 1
Integer 对象是不可变对象,假设 x 是一个 Integer,则 x++ 等同于 x = new Integer(x.intValue() + 1),但是你锁住的对象是之前的对象,是 x 引用了谁改变了,而不是 x 引用的那个谁改变了。
|
5
gtexpanse 2019-03-06 14:53:42 +08:00
++不是原子操作外加对象引用其实变了,所以没有锁住吧?
|
6
ipwx 2019-03-06 14: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 1
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 锁的是对象的引用。想了想只锁引用也确实不安全。应该是对象和引用都被锁了吧?
|