Java线程一致性问题

时间:2015-07-28 04:38:13

标签: 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()));
        }
    }
}

我有两个共享变量计数的线程,它定义为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后所看到的,Thread-1打印4。我的假设是Thread-1进入synchronized方法get并被thread-0的increment方法阻塞,一旦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());

1 个答案:

答案 0 :(得分:4)

这是一种竞争条件。 JVM不保证将多少个周期用于任一线程。所以挥发性工作,因为你没有看到相同的数字显示两次。但是,在两个线程中执行命令的顺序并不像您预期​​的那样。它没有去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都可以递增一个易失整数,然后等待CyclicBarrier让它们继续