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视频-->哔哩哔哩