Java线程一致性问题

Java Threads consistency issue

我有一个用例,我已经在一个小代码示例中复制了它:

package com.learning.thread;

public class ThreadInterupt {
    public volatile int count;

    public synchronized int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
    public synchronized void increment(){
        count++;
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadInterupt local = new ThreadInterupt();
        Thread firstThread = new Thread( new myThread(local));
        Thread secondThread = new Thread( new myThread(local));

        firstThread.start();
        secondThread.start();

        Thread.sleep(10);
        firstThread.interrupt();
        secondThread.interrupt();

    }
}

class myThread implements Runnable{
    static void threadMessage(String message) {
        String threadName =
            Thread.currentThread().getName();
        System.out.format("%s: %s%n",
                          threadName,
                          message);
    }

    ThreadInterupt global;

    public  myThread(ThreadInterupt local){
        global = local;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int i=0;
        while(i<5){
            if(Thread.interrupted()){
                threadMessage("Got Killed");
                break;
            }
            i++;
            global.increment();
            threadMessage(String.valueOf(global.getCount()));
        }
    }
}

我有两个线程共享一个变量 count ,它被定义为 volatile 。我在 ThreadInterupt class 中有两种方法,我在其中递增并获取计数变量,两者都定义为 synchronized 。我的问题是,虽然我希望第二个线程能够正确地获得增加的值,但它并没有这样做。我也在添加输出。

Thread-0: 1
Thread-1: 2
Thread-0: 3
Thread-0: 5
Thread-0: 6
Thread-0: 7
Thread-1: 4
Thread-1: 8
Thread-1: 9
Thread-1: 10

如您所见,线程 0 打印 7 后,线程 1 打印 4 。我在这里的假设是 Thread-1 进入同步方法 get 并被 thread-0 的增量方法阻塞,一旦它 thread-0 完成它打印出 get 。我不相信这一点。有人可以帮忙吗?

// 按照 codeBencher 的建议进行编辑,

这可能是因为延迟。当我将同步打印方法添加到 ThreadInterupt class 时,效果很好。

public synchronized void print(String threadName){
  System.out.println(threadName+String.valueOf(count));
 }

并在 运行 方法中

global.increment();
global.print(Thread.currentThread().getName());

这是一个竞争条件。 JVM 不保证有多少周期用于任一线程。所以 volatile 起作用了,因为您看不到相同的数字显示两次。但是跨两个线程执行命令的顺序可能与您预期的不同。它没有去 t-1 执行命令,现在 t-2 执行命令,现在又是 t-1,现在是 t-2。相反,它可能已经完成了 t-1、t-1、t-1、t-2、t-1、t-1、t-2、t-2、t-2、t-2、t-2。 ...等等等等。要强制它按照该顺序进行 t-1、t-2、t-1、t-2..,您将不得不使用 concurrent package 中的 类 的其他技术。

例如,一种常见的技术是使用 ConcurrentLatch 或 Future 来等待一个或多个其他线程完成。 CyclicBarrier 一个非常酷的可以用于倒计时(或向上计数)系统的系统是 CyclicBarrier,其中 t-1 和 t-2 可以各自递增一个 volatile 整数,然后等待 CyclicBarrier 让它们继续.