Java线程一致性问题

标签 java multithreading synchronized

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

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 类中有两个方法,我在其中递增并获取 count 变量,两者都定义了 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 类添加同步打印方法时,效果很好。

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

并在run方法中

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 是一个非常酷的系统,可以用于像这样的倒计时(或向上计数)系统。 ,其中 t-1 和 t-2 可以分别递增一个 volatile 整数,然后等待 CyclicBarrier 让它们继续。

关于Java线程一致性问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31667471/

相关文章:

java - 切换到全屏相机 OnClick

multithreading - 锁定集合的通常最佳方法是什么?

c++ - 使用线程改进功能

java - Java 信号量默认使用忙等待还是等待/通知?

java - Servlet 中的线程安全

java - Java Web 应用程序的无缝重新部署

java - 机器人 : rotate a high resolution picture generates an out of memory error

java - 如何为 Cewolf ChartProcessor 动态创建参数?

java - 同步线程抛出 CurrentModificationException

java - 2个线程如何在notifyAll之后获得锁?