Java线程计数器"问题"?

时间:2016-07-11 17:12:47

标签: java multithreading java-8

我正在尝试线程优先级的影响,当runln在run方法中保留在注释中时,两个线程同时结束并且我不理解这种行为,你能解释一下吗?谢谢。

Main.class

public class Main {

public static void main(String[] args) {
    Test t1 = new Test("Thread #1");
    Test t2 = new Test("Thread #2");

    t1.thread.setPriority(10);
    t2.thread.setPriority(1);

    t1.thread.start();
    t2.thread.start();

    try {
        t1.thread.join();
        t2.thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(t1.thread.getName() + ": " + t1.count);
    System.out.println(t2.thread.getName() + ": " + t2.count);

    System.out.println("End of main thread.");
}

}   

的Test.class

public class Test implements Runnable{ 
    public Thread thread;
    static boolean stop = false;
    int count = 0;

    public Test(String name){
        thread = new Thread(this, name);
    }

    @Override
    public void run(){

        for(int i = 0; i < 10000000 && stop == false; i++){
            count = i;
            //System.out.println(count + " " + thread.getName());
        }
        stop = true;

        System.out.println("End of " + thread.getName());
    }
}
     without println          with println

    End of Thread #1        End of Thread #1
    End of Thread #2        End of Thread #2
    Thread #1: 9999999      Thread #1: 9999999
    Thread #2: 9999999      Thread #2: 3265646
    End of main thread.     End of main thread.

2 个答案:

答案 0 :(得分:4)

您的两个线程在没有正确同步的情况下访问共享的可变变量。在这种情况下,没有关于线程何时(或者是否)将了解另一个线程所做更改的保证。在您的情况下,一个线程所做的更改根本不会被另一个线程注意到。请注意,对于像boolean这样的原始数据类型,不读取最新值是最糟糕的事情,对于非原始数据类型,甚至更糟的问题,即可能发生不一致的结果。

插入print语句具有同步线程的副作用,因为PrintStream执行内部同步。由于没有保证System.out将包含这样的同步打印流实现,这是一个特定于实现的副作用。

如果您将stop的声明更改为

static volatile boolean stop = false;

线程将在每次迭代中重新读取共享堆中的值,并立即对更改做出反应,但代价是降低整体性能。

请注意,仍然无法保证此代码按预期工作,因为没有任何保证,线程优先级没有任何影响,也没有线程并行运行。线程调度是实现和环境相关的行为。例如。你可能会发现优先级最高的线程不会先完成它的循环,而只是首先启动的线程。

答案 1 :(得分:3)

澄清:线程/进程&#34;优先级的唯一目的,&#34;在任何操作系统的任何语言环境中,建议到操作系统&#34;这两个中的哪一个应该是,认为,先运行& #39;&#34;如果他们两个碰巧是偶然的&#34;可跑的&#34;并且必须选择只运行其中一个。

(根据我的经验,这个实践中最好的例子是Unix / Linux nice命令,它自动以显着的数量减少命令的执行优先级。执行少量I / O的CPU密集型工作负载实际上可以中获得优先级降低。

正如其他回答者已经强调的那样,不可能预测&#34;实际会发生什么,&#34;永远不能用来改变这个前提。您必须显式使用适当的同步原语,以确保您的代码在所有情况下都能正常执行。