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
TL;DR-这是因为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)
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;