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 是(交替)并发执行的;,没有存在;
说原因
- 我也不知道,但是我猜一下吧;
- 一个线程获取的对象锁,一个线程获取的 是类锁;
参考资料
-
这位大哥,总结的很到位;,多看看;