请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

线程执行顺序问题(Synchronized、自旋锁)

悟空老师,我在做一道面试题遇到一个想不通的地方面试题如下:

public class TestSync2 implements Runnable {
    int b = 100;

    synchronized void m1() throws InterruptedException {
        b = 1000;
        Thread.sleep(500); //6
        System.out.println("b=" + b);
    }

    synchronized void m2() throws InterruptedException {
        Thread.sleep(250); //5
        b = 2000;
    }

    public static void main(String[] args) throws InterruptedException {
        TestSync2 tt = new TestSync2();
        Thread t = new Thread(tt);  //1
        t.start(); //2

        tt.m2(); //3
        System.out.println("main thread b=" + tt.b); //4
    }

    @Override
    public void run() {
        try {
            m1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这个程序的执行结果为什么会有:
main thread b=1000
b=1000
这种情况呢?
我先说一下我的理解,这道题主要是因为主线程和t线程开始执行顺序不同引起的结果不同,我假设主线程先执行,然后抢到了锁对象(this对象),然后线程睡眠250ms,此时t线程执行m1方法,因为锁对象已经被抢占,故自旋等待主线程释放锁对象,主线程执行完m2方法并释放锁对象,此时b=2000,那么为什么会出现上面main thread b = 1000的结果呢?

希望老师可以解惑。

正在回答

1回答

因为还没打印之前,m1就运行并修改了b,m1的速度比打印快,如果你在m1里的一开始加一句休眠5毫秒,,那结果就是2000,我刚才试过了。

2 回复 有任何疑惑可以回复我~
  • 提问者 superLiuLiuLiu #1
    但是不是有happens-before原则吗,在主线程之中m2方法的执行结果对主线程的打印可见,故应该是打印2000,希望老师可以帮我分析一下这个详细的流程(哪个线程先执行,锁的抢占情况),感觉有点懵了,非常感谢老师。
    回复 有任何疑惑可以回复我~ 2019-11-23 08:18:02
  • 悟空 回复 提问者 superLiuLiuLiu #2
    m2先运行,b变成了2000,然后m2运行完毕后,m1立刻运行并把b改成1000,此时主线程开始打印b,打印的锁和主线程子线程的锁不是同一把锁,打印出来main thread b=1000,500ms后,子线程的m1打印出b=1000。
    你可以把等待时间从500改成5000,从250改成2500,然后在m1里面的第一行sleep(5),然后debug,就很明显了。
    回复 有任何疑惑可以回复我~ 2019-11-23 10:39:39
  • 提问者 superLiuLiuLiu #3
    非常感谢!谢谢老师,理解了
    回复 有任何疑惑可以回复我~ 2019-11-23 11:16:48
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信