如何保证变量的可见性?
public class ThreadTest {
    public static void main(String[] args) {
        System.out.println("main: start");
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
        while (true) {
            if (runnable.getFlag()) {
                System.out.println("main: break");
                break;
            }
        }
        System.out.println("main: end");
    }
}

class MyRunnable implements Runnable {

    private boolean flag = false;

    @Override
    public void run() {
        System.out.println("run: start");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println("run: end");
    }

    public boolean getFlag() {
        return flag;
    }
}

运行输出:

main: start
run: start
run: end

main: break和main:end并未输出,有哪些解决方案?

方案1:使用volatile关键字

给flag字段加上volatile关键字,可以保证多线程的可见性

public class ThreadTest {
    public static void main(String[] args) {
        System.out.println("main: start");
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
        while (true) {
            if (runnable.getFlag()) {
                System.out.println("main: break");
                break;
            }
        }
        System.out.println("main: end");
    }
}

class MyRunnable implements Runnable {

    private volatile boolean flag = false;

    @Override
    public void run() {
        System.out.println("run: start");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println("run: end");
    }

    public boolean getFlag() {
        return flag;
    }
}

运行输出:

main: start
run: start
run: end
main: break
main: end

方案2:使用原子性操作

使用原子AtomicBoolean进行操作

import java.util.concurrent.atomic.AtomicBoolean;

public class ThreadTest {
    public static void main(String[] args) {
        System.out.println("main: start");
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
        while (true) {
            if (runnable.getFlag()) {
                System.out.println("main: break");
                break;
            }
        }
        System.out.println("main: end");
    }
}

class MyRunnable implements Runnable {

    private AtomicBoolean flag = new AtomicBoolean(false);

    @Override
    public void run() {
        System.out.println("run: start");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag.set(true);
        System.out.println("run: end");
    }

    public boolean getFlag() {
        return flag.get();
    }
}

运行输出:

main: start
run: start
run: end
main: break
main: end

方案3:使用synchronized进行代码块同步

public class ThreadTest {
    public static void main(String[] args) {
        System.out.println("main: start");
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
        while (true) {
            synchronized (ThreadTest.class) {
                // 同步代码执行完,工作内存数据会更新到主内存
                // 线程休眠,磁盘io等
            }
            if (runnable.getFlag()) {
                System.out.println("main: break");
                break;
            }
        }
        System.out.println("main: end");
    }
}

class MyRunnable implements Runnable {

    private boolean flag = false;

    @Override
    public void run() {
        System.out.println("run: start");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println("run: end");
    }

    public boolean getFlag() {
        return flag;
    }
}

运行输出:

main: start
run: start
run: end
main: break
main: end