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 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    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 锁的是对象的引用。想了想只锁引用也确实不安全。应该是对象和引用都被锁了吧? 
                 |