首页 > 解决方案 > 为什么我的线程在访问同步方法时会给我这个输出?

问题描述

我正在尝试多线程和同步,所以我创建了这个在所有线程之间共享的简单对象:

public class SharedObject {

    private int count = 0;

    public synchronized int getCount(){
        return count;
    }

    public synchronized void incrementCount(){
        count++;
    }
}

它由 3 个线程以这种方式访问​​:

public static void main(String[] args) throws Exception {


    SharedObject sharedObject = new SharedObject();
    ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);

    Runnable task = () -> {
        for(int i = 0; i < 10; i++){

            System.out.println("Thread : " + Thread.currentThread().getName() 
            + " count : " + sharedObject.getCount());

            sharedObject.incrementCount();

            try{
                Thread.currentThread().sleep(2000);
            }
            catch (Exception e){}
        }
    };

    executor.submit(task);
    executor.submit(task);
    executor.submit(task);

    executor.shutdown();
    executor.awaitTermination(1, TimeUnit.HOURS);

    System.out.println("Final : " + sharedObject.getCount());
}

我的输出如下:

Thread : pool-1-thread-2 count : 0
Thread : pool-1-thread-1 count : 0
Thread : pool-1-thread-3 count : 0
Thread : pool-1-thread-3 count : 3
Thread : pool-1-thread-2 count : 3
Thread : pool-1-thread-1 count : 3
Thread : pool-1-thread-2 count : 6
Thread : pool-1-thread-1 count : 6
Thread : pool-1-thread-3 count : 6
...

如果我的理解是正确的(如果我错了,请纠正我),这是因为:

  1. 第一个线程调用getCount(),获取方法上的锁,一旦他打印计数值,释放锁,然后由第二个线程获取,然后调用getCount()最后一个线程

  2. 当所有 3 个线程都完成调用getCount()时,它们中的每一个都在调用,incrementCount()并且由于方法是同步的,每个线程在增加计数之前都会看到更新的值,这解释了为什么我们在输出中看到 +3 的跳转

  3. 线程一结束,它就调用sleep(2000)自己,但由于调用速度如此之快,似乎三个线程同时开始和停止休眠

但是,当我删除时sleep(2000),我得到以下输出:

Thread : pool-1-thread-3 count : 0
Thread : pool-1-thread-2 count : 0
Thread : pool-1-thread-1 count : 0
Thread : pool-1-thread-2 count : 2
Thread : pool-1-thread-3 count : 1
Thread : pool-1-thread-2 count : 4
Thread : pool-1-thread-1 count : 3
Thread : pool-1-thread-2 count : 6
Thread : pool-1-thread-3 count : 5
Thread : pool-1-thread-2 count : 8
Thread : pool-1-thread-1 count : 7
Thread : pool-1-thread-2 count : 10
Thread : pool-1-thread-3 count : 9
Thread : pool-1-thread-2 count : 12
Thread : pool-1-thread-1 count : 11
Thread : pool-1-thread-2 count : 14

我不明白这怎么会发生。例如,如果在他之前看到计数等于2并增加它,怎么能thread-3看到计数等于1 ?thread-2

任何解释将不胜感激,以帮助我更好地理解多线程同步环境中的 Java。感谢您的时间。

标签: javamultithreadingconcurrencysynchronizationsynchronized

解决方案


仅仅因为一个线程在另一个之前读取一个值并不意味着它会在另一个之前打印它。Yo 需要在同步块内以原子方式完成读取和打印,以获得该保证。

所以你可以拥有的是

  • 线程 3 读取并打印值 (0): 线程:pool-1-thread-3 计数:0

  • 线程 2 读取并打印值 (0):线程:pool-1-thread-2 计数:0

  • 线程 1 读取并打印值 (0):线程:pool-1-thread-1 计数:0

  • 线程 3 递增值 (1)

  • 线程 3 读取值 (1)
  • 线程 2 递增值 (2)
  • 线程 2 读取并打印值 (2): 线程:pool-1-thread-2 计数:2
  • 线程 3 打印它之前读取的值: 线程 : pool-1-thread-3 count : 1

推荐阅读