线程同步的整数实例变量

时间:2021-09-28 21:02:48
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+" ");
        }
    }
}

Here i have synchronized on the variable ab. And i have created two different instances of class Check also, but i am always getting output for s1 followed by s2 or vice versa, but not mixed, why is that so? when i have already created two separate objects(in main), so two different threads, two different ab variables, so how it becomes a shared resource for the two different objects?

这里我对变量ab进行了同步,我也创建了两个不同的类检查实例,但是我总是得到s1的输出后面跟着s2,或者反过来,但不是混合的,为什么是这样?当我已经创建了两个独立的对象(主对象),两个不同的线程,两个不同的ab变量,那么它如何成为两个不同对象的共享资源呢?

3 个解决方案

#1


12  

TL;DR - it's because of Integer pooling. Make ab an Object (i.e. Object ab = new Object()) to guarantee that each instance of Check's locking doesn't interfere with the others.

TL;DR -这是因为整数池。使ab成为一个对象(即Object ab = new Object()),以保证每个Check的锁定实例不会干扰其他实例。


I was initially puzzled as well. Interestingly enough, if you change

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

private Integer ab = 2;

to

private Object ab = new Object();

the synchronization goes away (you get different outputs on every run). Back with ab as an Integer, I ran your code in debug mode (with a breakpoint on the print thread name line) and found the following. Here's the first thread:

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

线程同步的整数实例变量

And here's the second thread.

这是第二条线。

线程同步的整数实例变量

Notice that it's actually the same object, Integer@443. Even though you thought you were getting two different objects, both ab fields in the two Check instances refer to the same object in memory! Therefore yes, there is correct synchronization. The question, then, is how saying Integer ab = 2 twice gets you the same Integer object in memory.

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


By saying Integer ab = 2, you are using autoboxing, by which a primitive value (of type int) is automatically converted into the corresponding Object type Integer. This is equivalent to calling the autoboxing method call:

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

private Integer ab = Integer.valueOf(2);

If we look into Integer.valueOf, we notice that it has a pool for values within a certain range:

如果我们观察整数。valueOf,我们注意到它在一定范围内有一个值池:

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

For most conventional settings, this will include the value 2. Thus you are getting the same Integer value in memory when you call this method.

对于大多数常规设置,这将包括值2。因此,当您调用这个方法时,您将在内存中获得相同的整数值。

#2


4  

This is happening because of Ingeter Pool concept in java.

这是因为Ingeter池在java中的概念。

Integers ranging between -128 and 127 (inclusive), are used in same way as String pool.

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

So, when you use private Integer ab = 2;, ab is shared for both objects of Check.

因此,当您使用私有整数ab = 2时,ab对于检查的两个对象都是共享的。

You can use value > 128 or any other type of object so that your code won't be synchronized.

您可以使用值> 128或任何其他类型的对象,这样您的代码就不会被同步。

You may look at answers here: Why does the behavior of the Integer constant pool change at 127? for understanding Integer Pool concept.

您可以在这里查看答案:为什么整数常量池的行为在127时发生变化?为了理解整数池的概念。

#3


1  

If you take a look at bytecode you would probably see this code:

如果您查看字节码,您可能会看到以下代码:

LINENUMBER 15 L1
ALOAD 0
ICONST_2
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
PUTFIELD com/example/Check.ab : Ljava/lang/Integer;

Java tries to box the primitive value 2 to object by calling #valueOf of Integer class. And as we know, Integer's valueOf implements Flyweight pattern. Thus, the same object is shared between instances.

Java尝试通过调用Integer类的#valueOf来将原语值2设置为object。我们知道,整数的valueOf实现了Flyweight模式。因此,在实例之间共享相同的对象。

#1


12  

TL;DR - it's because of Integer pooling. Make ab an Object (i.e. Object ab = new Object()) to guarantee that each instance of Check's locking doesn't interfere with the others.

TL;DR -这是因为整数池。使ab成为一个对象(即Object ab = new Object()),以保证每个Check的锁定实例不会干扰其他实例。


I was initially puzzled as well. Interestingly enough, if you change

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

private Integer ab = 2;

to

private Object ab = new Object();

the synchronization goes away (you get different outputs on every run). Back with ab as an Integer, I ran your code in debug mode (with a breakpoint on the print thread name line) and found the following. Here's the first thread:

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

线程同步的整数实例变量

And here's the second thread.

这是第二条线。

线程同步的整数实例变量

Notice that it's actually the same object, Integer@443. Even though you thought you were getting two different objects, both ab fields in the two Check instances refer to the same object in memory! Therefore yes, there is correct synchronization. The question, then, is how saying Integer ab = 2 twice gets you the same Integer object in memory.

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


By saying Integer ab = 2, you are using autoboxing, by which a primitive value (of type int) is automatically converted into the corresponding Object type Integer. This is equivalent to calling the autoboxing method call:

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

private Integer ab = Integer.valueOf(2);

If we look into Integer.valueOf, we notice that it has a pool for values within a certain range:

如果我们观察整数。valueOf,我们注意到它在一定范围内有一个值池:

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

For most conventional settings, this will include the value 2. Thus you are getting the same Integer value in memory when you call this method.

对于大多数常规设置,这将包括值2。因此,当您调用这个方法时,您将在内存中获得相同的整数值。

#2


4  

This is happening because of Ingeter Pool concept in java.

这是因为Ingeter池在java中的概念。

Integers ranging between -128 and 127 (inclusive), are used in same way as String pool.

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

So, when you use private Integer ab = 2;, ab is shared for both objects of Check.

因此,当您使用私有整数ab = 2时,ab对于检查的两个对象都是共享的。

You can use value > 128 or any other type of object so that your code won't be synchronized.

您可以使用值> 128或任何其他类型的对象,这样您的代码就不会被同步。

You may look at answers here: Why does the behavior of the Integer constant pool change at 127? for understanding Integer Pool concept.

您可以在这里查看答案:为什么整数常量池的行为在127时发生变化?为了理解整数池的概念。

#3


1  

If you take a look at bytecode you would probably see this code:

如果您查看字节码,您可能会看到以下代码:

LINENUMBER 15 L1
ALOAD 0
ICONST_2
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
PUTFIELD com/example/Check.ab : Ljava/lang/Integer;

Java tries to box the primitive value 2 to object by calling #valueOf of Integer class. And as we know, Integer's valueOf implements Flyweight pattern. Thus, the same object is shared between instances.

Java尝试通过调用Integer类的#valueOf来将原语值2设置为object。我们知道,整数的valueOf实现了Flyweight模式。因此,在实例之间共享相同的对象。