Java 并发

多线程题分析

2019-01-18  本文已影响77人  Real_man

今天工作的时候,同事提出了一道多线程的题目,题目虽然比较简单,但是还是能考察对多线程,JMM的理解程度的。

情况1

以下代码程序能不能正常结束?为什么

public class TestThread implements Runnable {

    private boolean out = true;

    public static void main(String[] args) throws Exception {
        TestThread tt = new TestThread();
        Thread threadA = new Thread(tt);
        Thread threadB = new Thread(tt);
        threadA.start();
        threadB.start();
        Thread.sleep(5000L);
        tt.out = false;
        System.out.println("程序结束");
    }

    @Override
    public void run() {
        while (out) {

        }
    }
}

答案:
不能执行结束,原因我个人理解是每个线程都有自己的私有存储空间,第一次把out读到自己的线程私有空间之后,out的值变化没有影响到每个线程。

存放在堆上的对象可以被所有持有对这个对象引用的线程访问。当一个线程可以访问一个对象时,它也可以访问这个对象的成员变量。如果两个线程同时调用同一个对象上的同一个方法,它们将会都访问这个对象的成员变量,但是每一个线程都拥有这个本地变量的私有拷贝。

情况2

如果将out添加volatile之后,运行结果呢?

  private volatile boolean out = true;

答案:
能运行结束,因为volatile能保证线程的可见性和有序性,这样每次对out的操作都是再共享内存区操作的,每次去主内存读取数据,当out变为false之后,线程A,B都能感知的到。所以能正常结束

一个变量定义为volatile之后,可以保证次变了对所有线程的可见性,一条线程修改了这个值,新值对其它线程是可以立即得知的。

情况3

out不加volatile字段,但是在循环体中新建一个HashMap()对象,程序能不能正常结束呢?

public class TestThread implements Runnable {

    private boolean out = true;

    public static void main(String[] args) throws Exception {
        TestThread tt = new TestThread();
        Thread threadA = new Thread(tt);
        Thread threadB = new Thread(tt);
        threadA.start();
        threadB.start();
        Thread.sleep(5000L);
        tt.out = false;
        System.out.println("程序结束");
    }

    @Override
    public void run() {
        while (out) {
            new HashMap();
        }
    }
}

答案:
能运行结束,除了新建HashMap,新建重入锁,打印一行东西,程序都能运行结束。至于原理,这个目前还没有搞的太明白,希望有明白人能帮我解答

最后

有关最后一种情况,如果能解答,想必对JVM的底层应该理解的不错

参考

上一篇下一篇

猜你喜欢

热点阅读