当Integer对象用作同步块中的锁时,可能存在并发问题 - java

在处理多线程程序时,我观察到非常奇怪的行为。

当Integer对象用作锁时,似乎多个线程可以处于同步块中。
甚至认为这是意料之外的。

如果我在下面的程序中使用其他任何静态成员(如“s”,“o”和“c”)定义,则它将按预期工作。

码-

public class MyThread extends Thread{
    private static Integer ii=1;                        //Works fine
    private static Integer i=1;
    private static String s="1";                        //Works fine
    private static Object o= new Object();              //Works fine
    private static Class<MyThread> c= MyThread.class;   //Works fine

    public void run(){
        synchronized(i){
            System.out.print(i++ +" ");
            System.out.print(i+"   ");
        }
    }
    public static void main(String[] str) throws InterruptedException{
        for(int i=0;i<100;i++){
            MyThread t= new MyThread();
            t.start();
        }
        Thread.sleep(100);
        System.out.println();
        MyThread t= new MyThread();
        t.start();t.join();
        if(i!=102)
            System.out.println("fail");
    }
}

输出-

2 3   3 4   5 6   8 9   9 10   10 11 12   12 13   13 14   14 15   16 17   1 17   15 17   12   17 18   18 20   20 21   21 22   7 22 6 23   4 23   23 24   24 25   25 26   23   22   19 27   26 27   27 28   28 29   29 30   30 31   31 32   32 33   33 34   34 35   35 36   36 37   37 38   38 39   39 41   40 41 42   42   42 43   43 44 45   45   45 48   47 48   46 48   48 49   49 50   50 51   51 52   52 53   53 54   54 55   55 56   56 57   57 58   58 59   59 60   60 61   61 62   62 63 64   64 65   64   65 66   66 67   68 69   69 70   67 70   70 71   71 72   72 73   73 75   74 76   75 76   76 77   77 79 80   78 80   80   80 83 84   82 85   85 86   86 87   87 88   88 89   89 90   81 94   93 94   92 94   91 94   90 94   84   94 96   96 98   98 99   84 99   97 99   95 99   99 100   100 101   
101 102  

如您所见,当它打印“10 11 12”时,有两个线程在同步块中执行。

是我做错了事还是错过了什么?

是否与幕后的某些优化有关?
因为如果我使用“ii”来锁定,那么一切都将完美地工作。

同样,当使用'i'时,它也会打印'fail',但很少。

下面是用于运行该程序的Java版本。 java -version Java版本“1.7.0_51” Java(TM)SE运行时环境(内部版本
1.7.0_51-b13)Java HotSpot(TM)客户端VM(内部版本24.51-b03,混合模式,共享)

您可以使用下面的程序来运行该程序以运行这多次时间并查看结果。

public class MyThread extends Thread{
    private static Integer ii=1;
    private static Integer i=1;
    private static String s="1";
    private static Object o= new Object();
    private static Class<MyThread> c= MyThread.class;

    public void run(){
        synchronized(ii){
            System.out.print(i++ +" ");
            System.out.print(i+"   ");
        }
    }
    public static void main(String[] str) throws InterruptedException{
        for(int j=0;j<100;j++){
            for(int i=0;i<100;i++){
                MyThread t= new MyThread();
                t.start();
            }
            Thread.sleep(50);
            System.out.println();
            MyThread t= new MyThread();
            t.start();t.join();
            if(i!=102)
                System.out.println("fail");
            Thread.sleep(50);
            i=1;
            System.out.println();
        }
    }
}

参考方案

这个

i++

相当于

i = Integer.valueOf(i.intValue() + 1)

换句话说,i现在引用的对象与您最初在其上进行同步的对象不同。

如果在更改synchronized之后某个线程碰巧到达i块,它也将进入,因为它在另一个对象上获取了监视器。

因为如果我使用“ii”来锁定,那么一切都将完美地工作。

您不会在任何地方更改对ii的引用。

Java:静态字段在内存中的哪个位置? - java

如果我们将对象存储在对象的静态字段中,那么JVM如何为它分配内存?它是否存在于“隐式”(不确定我是否使用正确的单词)类对象中?静态字段与对象字段有何不同? 参考方案 静态字段是类变量,并且在该类的所有实例之间共享。实例变量(或我认为您引用它们的对象字段)属于类的各个实例,并且不共享。至于它们存储在内存中的位置将根据JVM的实现而定,因此没有理由需要两个不同的…

Java-搜索字符串数组中的字符串 - java

在Java中,我们是否有任何方法可以发现特定字符串是字符串数组的一部分。我可以避免出现一个循环。例如String [] array = {"AA","BB","CC" }; string x = "BB" 我想要一个if (some condition to tell wheth…

Java:正则表达式模式匹配器是否有大小限制? - java

我的模式类似于OR:“word1 | word2 | word3”我大约有800个字。可能有问题吗? 参考方案 您仅受记忆和理智的限制。 :)

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

Java Scanner读取文件的奇怪行为 - java

因此,在使用Scanner类从文件读取内容时,我遇到了一个有趣的问题。基本上,我试图从目录中读取解析应用程序生成的多个输出文件,以计算一些准确性指标。基本上,我的代码只是遍历目录中的每个文件,并使用扫描仪将其打开以处理内容。无论出于何种原因,扫描程序都不会读取其中的一些文件(所有UTF-8编码)。即使文件不是空的,scanner.hasNextLine()在…