为什么我的所有线程都使用相同的锁?

H-B*_*Bar 0 java concurrency synchronized

我最近遇到了这个代码片段

class Counter2 implements Runnable{

    private int value = 0;

    
    private Integer lock = 0;

    

    public void increment(){
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value++;
    }

    public void decrement(){
        value--;
    }

    public int getValue() {
        return value;
    }

    @Override
    public void run() {
        synchronized(lock) {
            this.increment();
            System.out.println(String.format("%s incremented value, value = %s", Thread.currentThread().getName(), this.value));
            this.decrement();
            System.out.println(String.format("%s decremented value, value = %s", Thread.currentThread().getName(), this.value));
        }
    }
}
public class Part8_synchronized_keyword_1 {
    
    public static void main(String[] args) {
        Counter2 counter = new Counter2();
        new Thread(counter,"Thread1").start();
        new Thread(counter,"Thread2").start();
        new Thread(counter,"Thread3").start();
        new Thread(counter,"Thread4").start();
        Counter2 counterB = new Counter2();
        new Thread(counterB, "ThreadB").start();

    }
}

Run Code Online (Sandbox Code Playgroud)

我得到的输出如下

Thread1 incremented value, value = 1
Thread1 decremented value, value = 0
ThreadB incremented value, value = 1
ThreadB decremented value, value = 0
Thread4 incremented value, value = 1
Thread4 decremented value, value = 0
Thread3 incremented value, value = 1
Thread3 decremented value, value = 0
Thread2 incremented value, value = 1
Thread2 decremented value, value = 0
Run Code Online (Sandbox Code Playgroud)

为什么看起来 threadB 正在与 thread1...4 竞争同一个锁?因为根据我的理解,counterB 和 counter 的锁对象会有所不同

Tho*_*ger 5

您认为countercounterB使用不同锁的假设是错误的

\n

为什么:因为你将你的锁声明为

\n
private Integer lock = 0;\n
Run Code Online (Sandbox Code Playgroud)\n

JVM 缓存Integer从 -128 到 127 之间所有值的对象。

\n

将你的锁声明为

\n
private Object lock = new Object();\n
Run Code Online (Sandbox Code Playgroud)\n

然后才会counter使用counterB不同的锁!

\n
\n

请注意对象引用和被引用对象之间的重要区别:

\n

counter都有counterB一个字段lock,但这些字段不是对象,它们只是对某个对象的引用。

\n

为了

\n
private Integer lock = 0;\n
Run Code Online (Sandbox Code Playgroud)\n

引用“某个对象”对于counterand来说是相同的counterB(因为 Java 语言规范要求将int-128 到 127 范围内的值装箱),并且同步发生在对象上,而不是引用上。

\n

摘自Java 语言规范,拳击转换

\n
\n

如果装箱的值是计算、、、、或p类型的常量表达式 (\xc2\xa715.29) 的结果,并且结果是、 、包含范围内的字符或范围内的整数为包容性,然后令和为 的任意两个装箱转换的结果。情况总是如此。booleanbytecharshortintlongtruefalse\'\\u0000\'\'\\u007f\'-128127abpa == b

\n
\n