面试题:synchronized 的用法

258 阅读2分钟

synchronized 的用法

  • 题目:一个类中有一个静态方法 A 和非静态方法 B,都被 synchronized 修饰。两个线程分别去调用同一个实例的方法 A 和方法 B,会产生竞争吗

  • ps: 看面经,是字节android岗位的面试题,管它是不是,还是要研究一下的,毕竟,这个题的答案,我也不敢确定;

Demo代码

  • 2 个线程,分别执行 对同一个变量 COUNT 执行 i++ 操作,然后,将放到 List 集合中
  • 变量:

// 竞争变量
private static final List<Integer> temp = new ArrayList<>();
// i++的变量
public static int COUNT = 0;
  • 线程
/**
 * 测试非静态方法
 */
static class TaskOne implements Runnable {
    private Demo_2 demo_2;

    public TaskOne(Demo_2 demo_2) {
        this.demo_2 = demo_2;
    }

    @Override
    public void run() {
        demo_2.testNonStaticMethod();
    }
}

/**
 * 测试静态方法
 */
static class TaskTwo implements Runnable {
    @Override
    public void run() {
        Demo_2.testStaticMethod();
    }
}

具体 加锁方法

  • 测试静态方法加锁,锁对象是Demo_2.class --->"类锁"
/**
 * 静态方法
 */
public static void testStaticMethod() {
    synchronized (Demo_2.class) {
        for (int i = 0; i < 5; i++) {
            COUNT++;
            try {
                temp.add(COUNT);
                System.out.println(Thread.currentThread().getName()+" : 静态函数在被调用...COUNT : " + COUNT);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
  • 非静态方法,锁对象是 this--->"对象锁"
/**
 * 非静态方法
 */
public void testNonStaticMethod() {
    synchronized (this) {
        for (int i = 0; i < 5; i++) {
            COUNT++;
            try {
                temp.add(COUNT);
                System.out.println(Thread.currentThread().getName()+" : 非静态函数在被调用...COUNT : " + COUNT);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
  • 测试 main 方法
public static void main(String[] args) {
    Demo_2 demo_2 = new Demo_2();
    TaskOne taskOne = new TaskOne(demo_2);
    TaskTwo taskTwo = new TaskTwo();
    Thread one = new Thread(taskOne,"taskOne");
    Thread two = new Thread(taskTwo,"taskTwo");

    // 启动线程
    two.start();
    one.start();

    Thread.State threadOneStatus = one.getState();
    Thread.State threadTwoStatus = two.getState();

    // 忙等,直到  Thread  one 和  Thread two 全部 运行结束,然后打印结果
    while (threadOneStatus != Thread.State.TERMINATED || threadTwoStatus != Thread.State.TERMINATED) {
        // 再次获取 ,为了print线程状态
        threadOneStatus = one.getState();
        threadTwoStatus = two.getState();
        System.out.println("taskOne 状态 : " + threadOneStatus.name());
        System.out.println("taskTwo 状态 : " + threadTwoStatus.name());
    }

    List<Integer> result = Demo_2.getTemp();
    System.out.println("result : " + result);
}
  • 打印结果:

taskTwo : 静态函数在被调用...COUNT : 2
taskOne 状态 : RUNNABLE
taskOne : 非静态函数在被调用...COUNT : 2
taskTwo 状态 : RUNNABLE
taskTwo : 静态函数在被调用...COUNT : 3
taskOne 状态 : BLOCKED
taskTwo : 静态函数在被调用...COUNT : 5
taskOne : 非静态函数在被调用...COUNT : 4
taskTwo : 静态函数在被调用...COUNT : 6
taskTwo 状态 : BLOCKED
taskOne 状态 : BLOCKED
taskTwo 状态 : BLOCKED
taskOne 状态 : BLOCKED
taskTwo : 静态函数在被调用...COUNT : 8
taskOne : 非静态函数在被调用...COUNT : 7
taskTwo 状态 : BLOCKED
taskOne : 非静态函数在被调用...COUNT : 9
taskOne 状态 : BLOCKED
taskTwo 状态 : TERMINATED
taskOne 状态 : BLOCKED
taskTwo 状态 : TERMINATED
taskOne 状态 : BLOCKED
taskTwo 状态 : TERMINATED
taskOne 状态 : BLOCKED
taskOne : 非静态函数在被调用...COUNT : 10
taskTwo 状态 : TERMINATED
taskOne 状态 : TERMINATED
taskTwo 状态 : TERMINATED
result : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • 结果很感人,居然是 10;正确

说结论

  • 从线程状态来看,从代码的执行顺序来看,taskOne 和 taskTwo 是(交替)并发执行的;,没有存在;

说原因

  • 我也不知道,但是我猜一下吧;
  • 一个线程获取的对象锁,一个线程获取的 是类锁;

参考资料