java 多线程 锁 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 = 2000
 * b=1000
 * 或者
 * main thread b = 1000
 * b=1000
 */

跟我自己做出来的答案肯定是有出入的,接下来是我自己的分析,大家有什么见解都可以留言,因为我对分析中的一个地方不太确定:

  • 首先从main开始执行,当t.start()后会开启一个线程,开启线程会耗费时间,而因为主线程正在运行,所以继续往下走
  • tt.m2(),主线程直接去调用了m2()方法,因为m2方法是同步的,所以此时是不会被t线程抢到的,Thread.sleep(250)会使主线程休眠,但是并不会释放锁,m2执行完成后,b=2000
  • 这时候t线程也启动好了,有线程的继承性得知在一个线程中开启另一个线程,这两个线程的优先级是相等的,所以t线程和主线程互抢执行权,这时就分两种执行情况了:

    • 主线程抢到执行权,则打印 main thread b=2000,接着t线程运行,run方法中调用了m1,b=1000,Thread.sleep(500),但是因为主线程已经没有代码可执行了,所以t线程醒后继续执行,打印b=1000
    • t线程抢到执行权,b=1000,Thread.sleep(500),睡眠后,主线程又抢到执行权,所以打印 main thread b=1000,然后t线程睡醒,打印b=1000

    在这个题中,因为加了锁,所以是不存在可见性问题的,我唯一不太确定的地方就是main方法中,t.start()后,是否是因为t.start()启动线程会花时间,所以继续让主线程执行到了tt.m2()方法,大家有什么见解的,可以留言一起讨论.
    关于synchronized关键字我们这里简单提一下:
    同步作用在以下3个地方:

  • 修饰方法(这时的锁就是此对象的实例this),一个线程在执行这个对象的同步方法时,其他线程不得执行同一个对象的同步方法,不过可以执行同一个对象的非同步方法和不同对象的同步方法
  • 同步代码块,一样的,synchronized(这里是对象锁){},只要对象锁一样,那一个线程在执行时,别的线程是无法执行的
  • 修饰静态方法,这时候只要是同一个类产生的实例,就被锁起来,不要求对象必须一致

猜你喜欢

转载自blog.csdn.net/lqx_sunhan/article/details/79069075
今日推荐