跳至主要內容

一个线程问题的记录

DHB大约 2 分钟Java线程

一个线程问题的记录

在线程中使用标识变量作为终止条件,可能导致无法结束

不阻塞

/**
 * @author donghaibin
 */
public class ThreadDemo {

    private static boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        newThread();
        running = false;
    }

    private static void newThread() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                while (running) {
                    
                }
            }
        };
        thread.start();
    }
}

这里不阻塞的原因:main函数是程序的入口,先执行,不让出CPU子线程无法执行。当执行newThread()创建一个子线程时,running已经等于false。

阻塞

/**
 * @author donghaibin
 */
public class ThreadDemo {

    private static boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        newThread();
        Thread.sleep(100);
        running = false;
    }

    private static void newThread() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                while (running) {
         
                }
            }
        };
        thread.start();
    }
}

这里原因和上面同理可得,主线程停止了100ms,让出了cpu执行子线程,running变量没有加volatile,无法保证可见性,当执行running = false时,对其他线程不可见。所以无法跳出while循环。

不阻塞

/**
 * @author donghaibin
 */
public class ThreadDemo {

    private static boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        newThread();
        Thread.sleep(100);
        running = false;
    }

    private static void newThread() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                while (running) {
                    System.out.println("---");
                }
            }
        };
        thread.start();
    }
}

这里不阻塞的原因:

先看下System.out.println的源码

    /**
     * Prints an integer and then terminate the line.  This method behaves as
     * though it invokes <code>{@link #print(int)}</code> and then
     * <code>{@link #println()}</code>.
     *
     * @param x  The <code>int</code> to be printed.
     */
    public void println(int x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

源码中存在synchronized

当线程释放一个锁时会强制性的将工作内存中之前所有的写操作都刷新到主内存中去,而获取一个锁则会强制性的加载可访问到的值到线程工作内存中来。虽然锁操作只对同步方法和同步代码块这一块起到作用,但是影响的却是线程执行操作所使用的所有字段。

所以执行println时,刷新了running

这里还存在一种可能:JVM优化,也叫作提升(hoisting)

https://hllvm-group.iteye.com/group/topic/34932#post-232535

https://github.com/sjsdfg/effective-java-3rd-chinese/blob/master/docs/notes/78.%20%E5%90%8C%E6%AD%A5%E8%AE%BF%E9%97%AE%E5%85%B1%E4%BA%AB%E7%9A%84%E5%8F%AF%E5%8F%98%E6%95%B0%E6%8D%AE.md

上次编辑于:
贡献者: dhb,donghaibin