我无法看到最终的计数器值为20000.这段代码出了什么问题?
public class Synchronize2 {
public static void main(String[] args) {
Threading t1 = new Threading();
Threading t2 = new Threading();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Threading.counter);
}
}
class Threading extends Thread {
static int counter;
public synchronized void incrementer() {
counter++;
}
public void run() {
for (int i=0; i<10000; i++) {
incrementer();
}
}
}
答案 0 :(得分:3)
您的同步incrementer
方法将锁定对象本身。但是你有两个不同的对象,每个对象都自己锁定,因此该方法不是线程安全的;两个线程仍然可以同时访问incrementer
。
此外,后增量操作不是线程安全的,因为它不是原子的;存在读操作和递增操作,并且可以在两个操作的中间中断线程。这个非线程安全的代码提供了一个竞争条件,其中线程1读取值,线程2读取值,然后线程一个增量和线程两个增量,但只有最后一个增量“获胜”并且一个增量丢失。当结束值小于20000时显示。
使方法static
也是如此,因为它是synchronized
,它将锁定类的类对象,这是正确的同步。
public static synchronized void incrementer() {
答案 1 :(得分:0)
您在两个不同的对象上进行同步。你的增量器是一个简短的形式:
public void incrementer() {
synchronized (this) {
counter++;
}
}
但是“this”的两个实例不是同一个Object。因此,您根本不进行同步。试试这种方式:
private static Object sync = new Object();
public void incrementer() {
synchronized (sync) {
counter++;
}
}
您还应该使变量计数器变为volatile。这不是严格必要的,因为您只在同步块中使用它。但是在实际代码中,您可能会在这样的块之外读取它,然后您将遇到问题。非易失性变量可以从本地线程缓存中读取,而不是从内存中读取。