与嵌套 class 但与全局变量同步? (JAVA)

Synchronization with nested class but with a global variable? (JAVA)

我想弄清楚用这种代码修复这个损坏的并发问题的最佳方法是什么。我试过在 "index++" 周围加一个锁,但是有没有更好的方法来实现并发?

    public class MainClass {
        public static short index = 0;

        public static void main(String[] args) {
            MainClass testConc = new MainClass();
            Thread thr1 = new Thread(testConc.new MyRunnable());
            thr1.start();
            Thread thr2 = new Thread(testConc.new MyRunnable());
            thr2.start();
        }    

        class MyRunnable implements Runnable {
            private static final Object lock = new Object();
            public void run() { 
                while (index < 99) {
                    System.out.println(index);
                    synchronized(lock) {
                        index++;
                    }
                }
            }
        }
    }

AtomicInteger 会比在索引周围锁定更好++ 它专为该用例而设计。

另外,通过锁定,您并没有实现并发,而是线程 safety/atomicity(如果实现正确)。

顺便说一下,我在您的代码中没有看到 'broken concurrency issue'。

您的锁应与其用于保护的数据处于同一级别 (MainClass)。 Class 变量 index 实际上应该有 private 作用域,因为同步只发生在-class.

此外,正如 Tomáš 在评论中指出的那样,该变量应标记为 volatile,这保证了对其值的任何更改对所有线程都是可见的(因为 Java 5 ).这消除了同步对 index 的读取访问的需要。所以更正后的代码看起来像:

public class MainClass {
  private static volatile short index = 0;
  private static final Object lock = new Object();
  ...

如果您希望程序按顺序输出从098的索引并且每个索引值只输出一次,您需要将run()方法修改为:

public void run() {
    while (index < 99) {
        synchronized (lock) {                    
            // double-check for threads that made it here
            // before #index got incremented to 99 by the thread that
            // made the final increment
            if (index < 99) {
                System.out.println(index);
                index++;
            }
        }
    }
}

请注意,index < 99double-check 是必需的,因为 index 可能已在 while 条件下计算值后被另一个线程更改。如果使用旧版本的 run().

增加 MainClass 生成的线程数,您会看到这一点