【问题标题】:Program not always terminating? [duplicate]程序不总是终止? [复制]
【发布时间】:2018-10-03 15:51:09
【问题描述】:

我想为我的一个项目测试多线程,同时尝试开发一个解决方案,以防出现问题。

所以我做了这个小测试:

主要

public class main
    {

        static int addToCounter;
        static int addToErrorCounter;
        public static void main(String[] args) throws InterruptedException
            {
                int threads = 10;
                Executor exec = new Executor();
                for (int i = 0; i < threads; i++)
                    {
                        double error = Math.random();
                        testClass aldo = new testClass();
                        Thread thread = aldo.getThread(300, error);
                        exec.execute(thread);
                    }
                while (threads != (addToCounter + addToErrorCounter))
                    {
                        System.out.println("Not all threads finished, number of finished threads is: " + (addToCounter + addToErrorCounter));
                        Thread.sleep(50);
                    }
                System.out.println("Number of Threads that finished correctly: " + addToCounter);
            }

    }

测试类

import test1.main;

public class testClass
    {

        public Thread getThread(long time, double error)
            {
                Thread thread = new Thread()
                    {

                        public void run()
                            {
                                try
                                    {
                                        Thread.sleep(time);
                                    }
                                catch (InterruptedException e)
                                    {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }

                                if (error > 0.5)
                                    {
                                        main.addToErrorCounter++;
                                        throw new java.lang.Error("HELLO");
                                    }
                                System.out.println("I DID THIS!");
                                main.addToCounter++;
                            }
                    };

                return thread;

            }

    }

(您必须修复导入,我也使用自定义类 Executor,尽管这只是 ExecutorService 的包装)

奇怪的行为是有时它可以正常工作,有时却不能(总终止线程数为 9,尽管我可以清楚地看到它打印了“我做到了!”并且错误正好 10 次)。

有什么办法吗?

【问题讨论】:

  • @Downvoter,想知道为什么投反对票?
  • 你为什么不让每个线程也说出它的名字,这样你就可以跟上哪个线程正在开始/结束,以及将线程数减少到 5 以帮助降低线程数故障排除?
  • 你说它的名字是什么意思?线程都使用相同的类,唯一的“移动”部分是Math.random()。我不明白这个名字在这里会有什么帮助。
  • What does your step debugger tell you? 这很容易理解,只需通过一步调试器即可。
  • Jarrod,这个问题与您列出的任何一个问题的 重复 有什么关系?当然,第一个是相关的,但是刚开始使用多线程 java 的初级程序员不太可能将该行识别为问题代码,然后考虑围绕原子性进行搜索。考虑到他们明显的技能水平,我觉得你给 OP 带来了过度的困难。

标签: java multithreading


【解决方案1】:

问题可能是竞态条件。 “++”运算符不是原子的。 想象以下场景。同时有两个线程。两者都想增加一个数字并完成。 该数字的初始值为 0。 线程 0 读取数字,现在知道它是 0。 线程 1 读取数字,现在知道它是 0。 线程 0(谁知道它是 0)现在将 1 写入内存。 线程 1 不知道数字已更改,但仍认为数字为 0,因此他也将 1 写入内存。

您需要诸如同步机制之类的东西,诸如锁之类的东西,或者信号量之类的东西。

查看此内容了解更多信息:http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/

对于您的示例,您可以使用该链接中的“同步”示例。

向您的主类添加一个方法,如下所示,以增加 addToCounteraddToErrorCounter 以消除错误计数器的影响:

synchronized AddToError(int e){
    addToError += e;
}
synchronized IncCounter(){
    addToCounter++;
}

在测试类的线程中调用这些方法,而不是不同步地递增它们。

【讨论】:

    【解决方案2】:

    我的猜测是后缀运算符 (main.addToCounter++) 不是原子的。这行代码可能相当于:

    int temp = main.addToCounter;
    main.addToCounter = temp + 1;
    return temp;
    

    多个线程同时执行此操作,两个线程可以获得相同的 temp 值(因为在执行第二行之前,两个线程都执行了上述伪代码中的第一行),因此计数器总数将一旦所有线程都完成,就太小了。请参阅Why is i++ not atomic? 了解更多信息。

    在这种情况下,一个快速解决方法是将 addToCounter 设为 AtomicInteger,然后使用 addToCounter.incrementAndGet() 代替 addToCounter++

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多