1

我是 Java 线程的新手,因此有这个疑问。我读到“同步的非静态方法块”只允许一个线程进入块(当然,对于非静态块的一个实例)。但是,它似乎不起作用。我错过了什么吗?看下面的代码。

class A extends Thread
{
    public void run() 
    {
        B.b.add();
    }
}

class B
{
    static B b=new B();
    int i;
    public synchronized void add()
    {
        i++;
    }
}

public class Sample
{
    public static void main(String[] args) 
    {
        for(int i=0;i<10;i++)
        {
            new A().start();
        }
        System.out.println(B.b.i);
    }
}
4

1 回答 1

2

这里的一个问题是您的主线程在尝试检索结果之前不会等待其他线程完成。如果您想等待单个线程,则使用 Thread#join 有效,但在这里我们希望等待所有 10 个线程。修改程序以使用 CountDownLatch 使主线程等待,直到它创建的所有线程都完成。

另一个问题是不能保证 i 的更新值是可见的。JVM 实现的不同在于它们执行优化的积极程度(例如延迟刷新缓存值或重新排序字节码)可能会使对 i 的更改对主线程不可见。在与 add 方法相同的锁上添加同步方法以获取 i 的值修复了可见性问题。

import java.util.concurrent.CountDownLatch;

class A extends Thread {
    private CountDownLatch latch;
    public A(CountDownLatch latch) {
        this.latch = latch;
    }    
    @Override public void run() {
        B.b.add();
        latch.countDown();
    }
}

class B {
    static B b=new B();
    int i;
    public synchronized void add() {
        i++;
    }
    public synchronized int getI() { 
        return i;
    }
}

public class Sample {
    public static void main(String[] args) throws Exception {
        CountDownLatch latch = new CountDownLatch(10);
        for(int i=0;i<10;i++) {
            new A(latch).start();
        }
        latch.await();     
        System.out.println(B.b.getI());
    }
}
于 2015-08-12T17:37:02.957 回答