线程"八锁" synchronized到底是对哪个对象加锁?
习题一
class Number{
public synchronized void a(){
System.out.println("1");
}
public synchronized void b(){
System.out.println("2");
}
}
public class TestBlock {
public static void main(String[] args) throws InterruptedException {
Number n = new Number();
Thread t1 = new Thread(()->{
System.out.println("t1->begin!!!");
n.a();
});
Thread t2 = new Thread(()->{
System.out.println("t2->begin!!!");
n.b();
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
对于Number类里面的a方法和b方法都是对当前对象this加锁,也就是对Number对象加锁.
当两个线程通过对象调用两个方法(a和b)的时候,会产生互斥效果-->锁的都是同一个对象(Number对象)
对于打印结果取决于任务调度器先调度谁就先打印谁,两者都有机会被优先调度,所以打印顺序可能是 1 2 也可能是2 1.
习题二
class Number1{
public synchronized void a(){
System.out.println("1");
}
public synchronized void b(){
System.out.println("2");
}
}
public class TestBlock1 {
public static void main(String[] args) throws InterruptedException {
Number1 n = new Number1();
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1->begin!!!");
n.a();
});
Thread t2 = new Thread(()->{
System.out.println("t2->begin!!!");
n.b();
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
对比习题1就相当于在t1线程里面多加了个sleep,让其t1线程睡眠一会.
但是,t1线程和t2线程锁的还是同一个对象Number具有互斥效果.
打印结果还是取决于任务调度器的调度,如果先调度的是t1(t1先拿到锁),那么就等待1s后,执行a方法打印1,然后线程2在执行b方法,打印2.
还有一种情况是任务调度器先调度t2线程,就会先打印2,然后睡眠1s后打印1.
习题3
class Number3{
public synchronized void a(){
System.out.println("1");
}
public synchronized void b(){
System.out.println("2");
}
public void c(){//没有加锁
System.out.println("3");
}
}
public class TestBlock3 {
public static void main(String[] args) throws InterruptedException {
Number3 n = new Number3();
Thread t1 = new Thread(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1->begin!!!");
n.a();
});
Thread t2 = new Thread(()->{
System.out.println("t2->begin!!!");
n.b();
});
Thread t3 = new Thread(()->{
System.out.println("t3->begin!!!");
n.c();
});
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
}
}
习题3是多加了一个方法c,但是方法c没有加synchronized.
对于这个题,方法a,b都加了synchronized可以其互斥效果,但是反方c没有加synchronized,不会被加锁.也就是线程1或者线程2执行,线程3不会阻塞,依然会继续往后执行.
对于打印结果还是取决于任务调度器的调度.
如果先调度的是线程1,那么会等待1s后打印1,但是方法c没有加锁,所以不会阻塞,线程3执行方法c打印3,然后1s后打印1 ,线程1释放锁之后唤醒线程2,线程2执行b方法打印2.====> 3 一秒后 1 2
由于线程2和线程3是并发执行的取决于任务调度器
如果先调度的是线程2,那么会先打印 2 ,然后线程3并发/并行的执行方法c打印3,然后一秒后打印1
===> 2 3 一秒后 1
如果先调度的是线程3,那么会先打印 3 ,然后线程2并发/并行的执行方法b打印2,然后一秒后打印1
===> 3 2 一秒后 1
习题4
class Number4{
public synchronized void a(){
System.out.println("1");
}
public synchronized void b(){
System.out.println("2");
}
}
public class TestBlock4 {
public static void main(String[] args) throws InterruptedException {
Number4 n1 = new Number4();
Number4 n2 = new Number4();
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1->begin!!!");
n1.a();
});
Thread t2 = new Thread(()->{
System.out.println("t2->begin!!!");
n2.b();
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
这个题有两个对象n1和n2.
有两个对象,n1.a(),n2.b(),既然是不同的对象,也就是线程1和线程2对不同的对象加锁=>锁的不是同一个对象不产生互斥效果,并发/并行的执行,但由于t1线程睡眠1s钟,所以总是先打印2 一秒后 在打印1
习题5
class Number5{
public synchronized static void a(){
System.out.println("1");
}
public synchronized void b(){
System.out.println("2");
}
}
public class TestBlock5 {
public static void main(String[] args) throws InterruptedException {
Number5 n = new Number5();
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1->begin!!!");
n.a();
});
Thread t2 = new Thread(()->{
System.out.println("t2->begin!!!");
n.b();
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
线程1调用a方法,a是静态方法,对静态方法加锁相当于是对类对象加锁-->锁的是Number类对象
线程2调用b方法,b是非静态方法,相当于对this对象加锁->也就是n对象
所以锁的是不同的对象==>对不同的对象进行加锁--->不会产生互斥效果
所以两线程是并发执行的,由于睡眠,先打印2,一秒后打印1
习题6
class Number6 {
public synchronized static void a(){
System.out.println("1");
}
public synchronized static void b(){
System.out.println("2");
}
}
public class TestBlock6 {
public static void main(String[] args) throws InterruptedException {
Number6 n = new Number6();
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1->begin!!!");
n.a();
});
Thread t2 = new Thread(()->{
System.out.println("t2->begin!!!");
n.b();
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
两个线程调用的方法都是对静态方法进行加锁==>都是对类对象加锁-->锁的是相同对象-->产生互斥效果.
取决于任务调度器. 先调度线程1就是 1s之后打印1 ,然后打印2,否则的话先调度线程2就是 打印2 ,1s之后然后打印1
习题7
class Number7 {
public synchronized static void a(){
System.out.println("1");
}
public synchronized void b(){
System.out.println("2");
}
}
public class TestBlock7 {
public static void main(String[] args) {
Number7 n1 = new Number7();
Number7 n2 = new Number7();
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
n1.a();
});
Thread t2 = new Thread(()->{
n2.b();
});
t1.start();
t2.start();
}
}
加锁的对象不一样,线程1调用的方法对类对象加锁,线程2里面利用n2对象调用b方法,对n2对象加锁,所以两个线程是对不同的对象进行加锁->不产生互斥效果.
所以线程1和线程2是并发执行的,所以是先打印2,一秒后打印1
习题8
class Number8{
public static synchronized void a() {
System.out.println("1");
}
public static synchronized void b() {
System.out.println("2");
}
}
public class TestBlock8 {
public static void main(String[] args) {
Number8 n1 = new Number8();
Number8 n2 = new Number8();
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
n1.a();
});
Thread t2 = new Thread(()->{
n2.b();
});
t1.start();
t2.start();
}
}
虽然是不同的对象调用方法
但是调用的方法都是对静态方法进行加锁==>都是对类对象加锁-->锁的是相同对象-->产生互斥效果.
取决于任务调度器. 先调度线程1就是 1s之后打印1 ,然后打印2,否则的话先调度线程2就是 打印2 ,1s之后然后打印1
总结
分析这种问题,首先往最根头看起,到底锁的对象是谁,是this还是类对象,还是没有加锁,然后在确定多个对象是否是锁的同一个对象
- 如果锁的是同一个对象,那么会产生互斥效果,一个线程没有执行完,另外一个线程阻塞等待.
- 锁的不是同一个对象,那么就不会产生互斥效果,并行的执行
- 如果没有加锁,那么也是会与其他线程并行的执行
然后具体情况具体分析,可能分为多种情况-->这种情况就要考虑任务调度器的调度执行了.--->分多种情况去考虑即可
参考 :
黑马程序员JUC视频-->哔哩哔哩