Java 整数实例变量上的线程同步 公共类主{ 公共静态void main(字符串[]args)引发异常{ //为类检查创建对象(2个不同的对象) 支票c=新支票(“s1”); 检查c1=新检查(“s2”); c、 start();c1.start(); } } 类检查扩展线程{ 检查(字符串名称){super(名称);} 私有整数ab=2; 公开募捐{ 同步(ab){ System.out.println(Thread.currentThread().getName()); 对于(int i=0;i

Java 整数实例变量上的线程同步 公共类主{ 公共静态void main(字符串[]args)引发异常{ //为类检查创建对象(2个不同的对象) 支票c=新支票(“s1”); 检查c1=新检查(“s2”); c、 start();c1.start(); } } 类检查扩展线程{ 检查(字符串名称){super(名称);} 私有整数ab=2; 公开募捐{ 同步(ab){ System.out.println(Thread.currentThread().getName()); 对于(int i=0;i,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,TL;DR-这是因为Integer池。将ab设为对象(即Object ab=new Object()),以确保检查的锁定的每个实例不会干扰其他实例 一开始我也很困惑。有趣的是,如果你改变了 public class Main{ public static void main(String[] args) throws Exception { // Creating objects for class Check(2 different objects)

TL;DR-这是因为
Integer
池。将ab设为
对象
(即
Object ab=new Object()
),以确保
检查
的锁定的每个实例不会干扰其他实例


一开始我也很困惑。有趣的是,如果你改变了

public class Main{
    public static void main(String[] args) throws Exception {
        // Creating objects for class Check(2 different objects)
        Check c = new Check("s1");
        Check c1 = new Check("s2");
        c.start();c1.start();
   }
}
class Check extends Thread{
    Check(String name){super(name);}
    private Integer ab = 2;
    public void run(){
        synchronized (ab) {
            System.out.println(Thread.currentThread().getName());
            for(int i=0;i<10;i++)System.out.print(i+" ");
        }
    }
}

同步消失了(每次运行都会得到不同的输出)。回到ab作为一个
整数的情况下,我在调试模式下运行了代码(在打印线程名称行上有一个断点),发现了以下内容。这是第一个线程:

这是第二条线索

请注意,它实际上是同一个对象,
Integer@443
。即使您认为得到的是两个不同的对象,但两个检查实例中的
ab
字段都引用了内存中的同一个对象!因此,是的,存在正确的同步。那么,问题是如何两次说
Integer ab=2
您可以在内存中创建相同的
整数
对象


通过说
Integer ab=2
,您正在使用自动装箱,通过这种方式,一个原语值(类型
int
)将自动转换为相应的对象类型
Integer
。这相当于调用自动装箱方法调用:

private Object ab = new Object();
如果查看
Integer.valueOf
,我们会注意到它有一个特定范围内的值池:

private Integer ab = Integer.valueOf(2);
公共静态整数值(int i){

如果(i>=IntegerCache.low&&i查看字节码,您可能会看到以下代码:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

Java试图通过调用
Integer
类的
#valueOf
将原始值
2
装箱到对象中。正如我们所知,
Integer
valueOf
实现了模式。因此,相同的对象在实例之间共享。

这是因为Java中的Ingeter Pool概念

介于-128和127(含)之间的整数的使用方式与字符串池相同

因此,当您使用
private Integer ab=2;
时,
Check
的两个对象都共享ab

您可以使用value>128或任何其他类型的对象,以便代码不会同步


您可以在这里查看答案:了解整数池概念。

非常有趣。非常感谢。:)特定范围默认情况下是从-128到127。请注意,IntegerCache.high可以更改。IntegerCache.low不能。B.t.W.,您不是在变量上同步,而是在变量引用的对象上同步。这是一个重要的区别,因为有些人犯了错误,没有意识到变量可以引用不同的对象T在不同的时间,有些人犯了一个错误,没有意识到同一个对象可以被多个变量引用。这段代码看起来更像是一个测试代码,而不是一个真实的案例,但是如果你想在无锁但线程安全的情况下进行同步,你可以使用。@jameslarge:我明白,你在说什么。我对b不太清楚因为我的问题集中在其他方面。无论如何,谢谢。)@Jean-FrançoisSavard:是的,这是一个测试代码,与实际项目无关。只是看看。是的,AtomicInteger,我知道。谢谢。:@Jean-François:澄清一下,AtomicInteger更像是锁定的替代品,它不应该用作锁定。如果你需要显式不同的对象,你应该显式创建它们。使用大型在当前的实现中,r整数将为您提供不同的对象,但不需要这样做。
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
LINENUMBER 15 L1
ALOAD 0
ICONST_2
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
PUTFIELD com/example/Check.ab : Ljava/lang/Integer;