同一个类中多个持有不同锁的同步代码块会不会阻塞--关于同步代码块的一个疑问验证--

时间:2022-09-28 11:18:31

结论是:

在同一个类中,多个线程同时访问同一对象的持有不同锁的同步代码块不会发生阻塞。

一、直接测试。供测试的共享对象的类:(方法changeA,changB持不同锁)

public class Demo {
    //新建两个对象供同步代码块加锁
    Student a = new Student(1, "A");
    Student b = new Student(2, "B");
    public void changeA() {
        //加锁a
        synchronized (a) {
            System.out.println(Thread.currentThread().getName() + "进入同步代码块的时间:" + System.currentTimeMillis());
            a.setId(3);
            //为了观察明显,线程持锁跑3s
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
            }
            System.out.println(Thread.currentThread().getName() + "退出代码块的时间:" + System.currentTimeMillis());
        }
    }
    public void changeB() {
        //加锁b
        synchronized (b) {
            System.out.println(Thread.currentThread().getName() + "进入同步代码块的时间:" + System.currentTimeMillis());
            b.setId(4);
            //为了观察明显,线程持锁跑3s
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
            }
            System.out.println(Thread.currentThread().getName() + "退出代码块的时间:" + System.currentTimeMillis());
        }
    }
    public Student getA() {
        return a;
    }
    public Student getB() {
        return b;
    }
}

Student类包含id和name属性;

测试方法:

public class Main {
    public static void main(String[] args) {
        Demo demo = new Demo();
        //新建两个线程分别进入changeA,changeB方法,验证是否会阻塞
        Thread threada = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("--a的初始值"+demo.getA());
                demo.changeA();
                System.out.println("--a更新后值"+demo.getA());
            }
        });
        Thread threadb = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("b的初始值"+demo.getB());
                demo.changeB();
                System.out.println("--b更新后值"+demo.getB());
            }
        });
        //线程跑起来
        threada.start();
        threadb.start();
    }
}

结果截图:

同一个类中多个持有不同锁的同步代码块会不会阻塞--关于同步代码块的一个疑问验证--

发现a,b基本是无时间差的先后进行,3s后也是基本无时间差的先后结束。

二、反向验证一下:

将Demo类changB方法持有的锁也改成a;(两个同步代码块持同一对象锁)

    public void changeA() {
        //加锁a
        synchronized (a) {
            System.out.println(Thread.currentThread().getName() + "进入同步代码块的时间:" + System.currentTimeMillis());
            a.setId(3);
            //为了观察明显,线程持锁跑3s
            try {
                Thread.sleep(3000);
            } catch (Exception e) {

            }
            System.out.println(Thread.currentThread().getName() + "退出代码块的时间:" + System.currentTimeMillis());
        }
    }

    public void changeB() {
        //加锁b
        synchronized (a) {
            System.out.println(Thread.currentThread().getName() + "进入同步代码块的时间:" + System.currentTimeMillis());
            b.setId(4);
            //为了观察明显,线程持锁跑3s
            try {
                Thread.sleep(3000);
            } catch (Exception e) {

            }
            System.out.println(Thread.currentThread().getName() + "退出代码块的时间:" + System.currentTimeMillis());
        }
    }

验证结果:

同一个类中多个持有不同锁的同步代码块会不会阻塞--关于同步代码块的一个疑问验证--

Thread0执行3秒完后,Thread1才执行,也花费3秒。