与嵌套 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();
...
如果您希望程序按顺序输出从0
到98
的索引并且每个索引值只输出一次,您需要将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 < 99
的 double-check 是必需的,因为 index
可能已在 while
条件下计算值后被另一个线程更改。如果使用旧版本的 run()
.
增加 MainClass
生成的线程数,您会看到这一点
我想弄清楚用这种代码修复这个损坏的并发问题的最佳方法是什么。我试过在 "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();
...
如果您希望程序按顺序输出从0
到98
的索引并且每个索引值只输出一次,您需要将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 < 99
的 double-check 是必需的,因为 index
可能已在 while
条件下计算值后被另一个线程更改。如果使用旧版本的 run()
.
MainClass
生成的线程数,您会看到这一点