如何防止关键部分中的上下文切换

时间:2017-12-22 14:29:51

标签: java multithreading

我有以下代码:

import java.util.ArrayList;

public class main {
    final static Object lock= new Object();
    public static void main(String[] args) {

        for (int i = 0; i < 100000; i++) {

            System.out.println("-------");
            finish finished = new finish(false);
            ArrayList<Boolean> arr = new ArrayList<>();

            Thread t1 = new Thread(() -> {
                System.out.println(Thread.currentThread().getId() + " Is setting");
                finished.setFinished(true);

            });


            t1.start();
            synchronized (lock){
                if (finished.isFinished == false) {
                    System.out.println(Thread.currentThread().getId() + " Is adding");
                    arr.add(new Boolean(finished.isFinished));
                } else {
                    System.out.println("Done");
                }
            }


            System.out.println("The length of array is " + arr.size());
            if (arr.size() > 0) {
                System.out.println("The val of array is " + arr.get(0));
            }
        }
    }
}

class finish {
    public boolean isFinished = false;

    public finish(boolean finished) {
        this.isFinished = finished;
    }

    public void setFinished(boolean finished) {
        this.isFinished = finished;

    }

}

我希望得到以下输出:

数组的长度为1
数组的val为false

完成

大多数情况都是如此。 但有时输出是:

数组的长度为1
数组的val是真的

这意味着,关键部分中存在上下文切换。 我试图在一个对象上同步代码,但它没有帮助。 这是一个经典的同步问题,但我无法解决它。 也许我应该使用原子对象,但我不知道它们在这种情况下会有什么帮助。 或许我对java很苛刻,我不应该在for循环中测试它?我在Linux操作系统上运行此示例。 我认为我的同步没有意义。但我不知道如何解决它。

2 个答案:

答案 0 :(得分:2)

您的示例代码尝试做什么并不清楚,但如果您想等待线程完成,请使用t1.join()并处理此引发的InterruptedException。此外,如果您要在多个主题中使用finishedAtomicBoolean应该是2017.12.22 07:52:27 INFO app[][o.e.p.PluginsService] no modules loaded 2017.12.22 07:52:27 INFO app[][o.e.p.PluginsService] loaded plugin [org.elasticsearch.transport.Netty4Plugin] 2017.12.22 07:52:35 INFO app[][o.s.a.SchedulerImpl] Process[es] is up 2017.12.22 07:52:35 INFO app[][o.s.a.p.ProcessLauncherImpl] Launch process[[key='web', ipcIndex=2, logFilenamePrefix=web]] from [/opt/sonarqube]: /opt/IBM/WebSphere/AppServer/java_1.8_64/jre/bin/java -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/opt/sonarqube/temp -Xms512m -XX:+HeapDumpOnOutOfMemoryError -server -cp ./lib/common/*:./lib/server/*:/opt/sonarqube/lib/jdbc/postgresql/postgresql-42.1.4.jar org.sonar.server.app.WebServer /opt/sonarqube/temp/sq-process7192036004631233695properties 2017.12.22 07:52:42 INFO app[][o.s.a.SchedulerImpl] Process [web] is stopped 2017.12.22 07:52:42 WARN app[][o.s.a.p.AbstractProcessMonitor] Process exited with exit value [es]: 143 2017.12.22 07:52:42 INFO app[][o.s.a.SchedulerImpl] Process [es] is stopped 2017.12.22 07:52:42 INFO app[][o.s.a.SchedulerImpl] SonarQube is stopped

但总而言之,代码存在问题,并不反映您尝试处理的任何现实场景。

答案 1 :(得分:0)

在此代码中,您正在读取相同的变量两次,这样就可以更改它。最简单的解决方案是只读一次。

boolean isFinished = finished.isFinished;
if (isFinished) {
    System.out.println("Done");
} else {
    System.out.println(t1 + " Is adding");
    arr.add(isFinished);
}