2

请看下面的程序

public class TestVolatile implements Runnable {

    public static volatile int counter;
    public static String lock = "lock";

    public static void main(String[] args) {
        Thread t1 = new Thread(new TestVolatile(),"Thread-1");
        Thread t2 = new Thread(new TestVolatile(),"Thread-2");
        t1.start();
        t2.start();
    }

    public void run() {
        synchronized(this) {
            System.out.println(Thread.currentThread()+"-"+counter);
            counter++;
        }
    }
}

如果我多次运行这个程序,我会得到 3 个不同的结果。

首先是

线程[Thread-1,5,main]-0
线程[Thread-2,5,main]-0

第二个是

线程[Thread-1,5,main]-0
线程[Thread-2,5,main]-1

第三是

线程[Thread-1,5,main]-1
线程[Thread-2,5,main]-0

但是如果将锁定对象从“this”更改为“lock”,我会得到 2 个不同的结果

首先是

线程[Thread-1,5,main]-0
线程[Thread-2,5,main]-1

第二个是

线程[Thread-1,5,main]-1
线程[Thread-2,5,main]-0

我在编写程序时的假设是,在任何一种情况下,“计数器”都不应该在两个语句中都为 0。
有人可以解释一下吗?

4

2 回答 2

3

您创建了两个 TestVolatile 对象。“this”关键字指的是在线程中运行的 TestVolatile 对象。因此,您不会在第一个示例中对同一对象进行同步。

如果您像这样更改代码,那么第一个示例开始工作:

public static void main(String[] args) {
    TestVolatile testVolatile = new TestVolatile();
    Thread t1 = new Thread(testVolatile,"Thread-1");
    Thread t2 = new Thread(testVolatile,"Thread-2");
    t1.start();
    t2.start();
}
于 2012-04-26T06:23:40.973 回答
1

这可能不是您要查找的内容,但如果您想避免使用synchronizedand volatile,您应该使用以下实例AtomicIntegerhttp ://docs.oracle.com/javase/6/docs/api/java/util/并发/原子/AtomicInteger.html

使用该getAndIncrement方法显示与您的示例相同的行为。

public class TestVolatile implements Runnable {

    public static AtomicInteger counter = new AtomicInteger();
    public static void main(String[] args) {
        Thread t1 = new Thread(new TestVolatile(),"Thread-1");
        Thread t2 = new Thread(new TestVolatile(),"Thread-2");
        t1.start();
        t2.start();
    }

    public void run() {
        System.out.println(Thread.currentThread() + " - " + counter.getAndIncrement());
    }

}
于 2012-04-26T06:35:19.703 回答