首页 > 解决方案 > 什么时候应该声明一个方法是同步的?

问题描述

以下是一个简单的工作程序,它使用两个线程来打印一个计数器:

public class SynchronizedCounter implements Runnable {

    private static int i = 0;

    public void increment() { i++; }
    public int getValue() { return i; }  

    @Override
    public void run() {
        for( int i = 0; i < 5; i++ ) {
            synchronized( this ) {
                increment();
                System.out.println( Thread.currentThread().getName() + " counter: " + this.getValue() );
            }
        }
    }

    public static void main( String[] args ) {

        ExecutorService executorService = Executors.newFixedThreadPool( 2 );
        SynchronizedCounter synchronizedCounter = new SynchronizedCounter();
        executorService.submit( synchronizedCounter );
        executorService.submit( synchronizedCounter );  
        executorService.shutdown();

    }

}

输出如预期 - 两个线程按顺序显示计数器。

如果increment()getValue()被声明为synchronizedsynchronized块代码被注释,输出显示可见性和竞争问题。

As increment()and getValue()are not declared as and by, 只是,如果可以实现同步,则synchronized使用块(传递监视器对象),在什么情况下应将它们声明为?synchronizedsynchronized

标签: javamultithreadingconcurrencythread-synchronization

解决方案


当您需要方法主体周围的同步块的语义时,声明方法同步。

synchronized void increment() {
  ...
}

与以下内容完全相同:

void increment() {
  synchronized (this) { ... }
}

在上面的代码中这样做的事情是您不再以原子方式执行increment()andgetValue()方法:另一个线程可以在线程调用之间插入并执行方法:

Thread 1             Thread 2

increment()
                     increment()
                     getValue()
getValue()

这是可能的,但是两个线程不能同时执行increment()(或getValue()),因为它们是同步的(*)。

另一方面,在问题中的代码中同步调用意味着这两个调用是原子执行的,因此两个线程不能交错:

Thread 1             Thread 2

increment()
getValue()
                     increment()
                     getValue()

(*) 实际上,它们可以同时执行该方法。只是除了一个线程之外的所有线程都将在synchronized (this).


推荐阅读