【问题标题】:Synchronization Block同步块
【发布时间】:2015-05-25 12:54:14
【问题描述】:

我是 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);
    }
}

【问题讨论】:

  • 等等,是不是跟缓存写策略有关?因为我预计会打印一个结果“10”,但结果是随机的,从 0 到 9。
  • 抱歉,知道了。主线程在值被所有线程递增之前打印该值(因为并行执行)。所有线程完成执行后如何打印值?
  • 如果你想等待所有线程,你必须在循环后加入它们,请参阅:docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()

标签: java multithreading synchronization synchronized java-threads


【解决方案1】:

这里的一个问题是您的主线程在尝试检索结果之前不会等待其他线程完成。如果您想等待单个线程,则使用 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());
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2011-12-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多