【问题标题】:Java threads counter "issue"?Java线程计数器“问题”?
【发布时间】:2016-11-13 17:34:49
【问题描述】:

我正在尝试线程优先级的影响,当运行方法中的 println 停留在注释中时,两个线程同时结束,我不明白这种行为,你能解释一下吗?谢谢。

主类

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.

【问题讨论】:

  • 您期望什么行为?你的电脑有几个核心?你认为线程优先级是多少?
  • “两个线程同时结束”是什么意思?您对这种行为有什么不理解的地方?
  • 您的输出描述了正确的行为。您还有什么期望?
  • 我不知道为什么没有 print 它们会同时结束,而当我将 print 与 counter 一起循环时它们不会。我的电脑有 2 核 / 4 线程。

标签: java multithreading java-8


【解决方案1】:

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

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

如果将stop的声明改为

static volatile boolean stop = false;

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

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

【讨论】:

    【解决方案2】:

    澄清一下:在任何操作系统上的任何语言环境中,线程/进程“优先级”的唯一目的是向操作系统建议“这两者中的哪一个应该是,我认为,先运行',”如果它们恰好都可以瞬间“运行”并且必须选择只运行其中一个。

    (根据我的经验,这种实践中最好的例子是 Unix/Linux nice 命令,它自愿将命令的执行优先级显着降低。) CPU - 执行少量 I/O 的密集型工作负载实际上可以受益降低优先级。

    正如其他回答者已经强调的那样,不可能预测“实际会发生什么”,并且永远不能使用优先级来改变这个前提。您必须明确使用适当的同步原语来确保您的代码在所有情况下都能正确执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-18
      • 1970-01-01
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      相关资源
      最近更新 更多