方法同步线程问题

时间:2014-01-10 16:47:55

标签: java multithreading synchronized

我无法看到最终的计数器值为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();
        }
    }
}

2 个答案:

答案 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。这不是严格必要的,因为您只在同步块中使用它。但是在实际代码中,您可能会在这样的块之外读取它,然后您将遇到问题。非易失性变量可以从本地线程缓存中读取,而不是从内存中读取。