• 线程“八锁“ synchronized到底是对哪个对象加锁?


    线程"八锁" synchronized到底是对哪个对象加锁?

    习题一

    1. class Number{
    2. public synchronized void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized void b(){
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock {
    10. public static void main(String[] args) throws InterruptedException {
    11. Number n = new Number();
    12. Thread t1 = new Thread(()->{
    13. System.out.println("t1->begin!!!");
    14. n.a();
    15. });
    16. Thread t2 = new Thread(()->{
    17. System.out.println("t2->begin!!!");
    18. n.b();
    19. });
    20. t1.start();
    21. t2.start();
    22. t1.join();
    23. t2.join();
    24. }
    25. }

    对于Number类里面的a方法和b方法都是对当前对象this加锁,也就是对Number对象加锁.

    当两个线程通过对象调用两个方法(a和b)的时候,会产生互斥效果-->锁的都是同一个对象(Number对象)

    对于打印结果取决于任务调度器先调度谁就先打印谁,两者都有机会被优先调度,所以打印顺序可能是 1 2 也可能是2 1.

    习题二

    1. class Number1{
    2. public synchronized void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized void b(){
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock1 {
    10. public static void main(String[] args) throws InterruptedException {
    11. Number1 n = new Number1();
    12. Thread t1 = new Thread(()->{
    13. try {
    14. Thread.sleep(1000);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. System.out.println("t1->begin!!!");
    19. n.a();
    20. });
    21. Thread t2 = new Thread(()->{
    22. System.out.println("t2->begin!!!");
    23. n.b();
    24. });
    25. t1.start();
    26. t2.start();
    27. t1.join();
    28. t2.join();
    29. }
    30. }

    对比习题1就相当于在t1线程里面多加了个sleep,让其t1线程睡眠一会.

    但是,t1线程和t2线程锁的还是同一个对象Number具有互斥效果.

    打印结果还是取决于任务调度器的调度,如果先调度的是t1(t1先拿到锁),那么就等待1s后,执行a方法打印1,然后线程2在执行b方法,打印2.

    还有一种情况是任务调度器先调度t2线程,就会先打印2,然后睡眠1s后打印1.

    习题3

    1. class Number3{
    2. public synchronized void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized void b(){
    6. System.out.println("2");
    7. }
    8. public void c(){//没有加锁
    9. System.out.println("3");
    10. }
    11. }
    12. public class TestBlock3 {
    13. public static void main(String[] args) throws InterruptedException {
    14. Number3 n = new Number3();
    15. Thread t1 = new Thread(()->{
    16. try {
    17. Thread.sleep(10000);
    18. } catch (InterruptedException e) {
    19. e.printStackTrace();
    20. }
    21. System.out.println("t1->begin!!!");
    22. n.a();
    23. });
    24. Thread t2 = new Thread(()->{
    25. System.out.println("t2->begin!!!");
    26. n.b();
    27. });
    28. Thread t3 = new Thread(()->{
    29. System.out.println("t3->begin!!!");
    30. n.c();
    31. });
    32. t1.start();
    33. t2.start();
    34. t3.start();
    35. t1.join();
    36. t2.join();
    37. t3.join();
    38. }
    39. }

    习题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

    1. class Number4{
    2. public synchronized void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized void b(){
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock4 {
    10. public static void main(String[] args) throws InterruptedException {
    11. Number4 n1 = new Number4();
    12. Number4 n2 = new Number4();
    13. Thread t1 = new Thread(()->{
    14. try {
    15. Thread.sleep(1000);
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. System.out.println("t1->begin!!!");
    20. n1.a();
    21. });
    22. Thread t2 = new Thread(()->{
    23. System.out.println("t2->begin!!!");
    24. n2.b();
    25. });
    26. t1.start();
    27. t2.start();
    28. t1.join();
    29. t2.join();
    30. }
    31. }

    这个题有两个对象n1和n2.

    有两个对象,n1.a(),n2.b(),既然是不同的对象,也就是线程1和线程2对不同的对象加锁=>锁的不是同一个对象不产生互斥效果,并发/并行的执行,但由于t1线程睡眠1s钟,所以总是先打印2 一秒后 在打印1

    习题5

    1. class Number5{
    2. public synchronized static void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized void b(){
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock5 {
    10. public static void main(String[] args) throws InterruptedException {
    11. Number5 n = new Number5();
    12. Thread t1 = new Thread(()->{
    13. try {
    14. Thread.sleep(1000);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. System.out.println("t1->begin!!!");
    19. n.a();
    20. });
    21. Thread t2 = new Thread(()->{
    22. System.out.println("t2->begin!!!");
    23. n.b();
    24. });
    25. t1.start();
    26. t2.start();
    27. t1.join();
    28. t2.join();
    29. }
    30. }

    线程1调用a方法,a是静态方法,对静态方法加锁相当于是对类对象加锁-->锁的是Number类对象

    线程2调用b方法,b是非静态方法,相当于对this对象加锁->也就是n对象

    所以锁的是不同的对象==>对不同的对象进行加锁--->不会产生互斥效果

    所以两线程是并发执行的,由于睡眠,先打印2,一秒后打印1

    习题6

    1. class Number6 {
    2. public synchronized static void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized static void b(){
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock6 {
    10. public static void main(String[] args) throws InterruptedException {
    11. Number6 n = new Number6();
    12. Thread t1 = new Thread(()->{
    13. try {
    14. Thread.sleep(1000);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. System.out.println("t1->begin!!!");
    19. n.a();
    20. });
    21. Thread t2 = new Thread(()->{
    22. System.out.println("t2->begin!!!");
    23. n.b();
    24. });
    25. t1.start();
    26. t2.start();
    27. t1.join();
    28. t2.join();
    29. }
    30. }

    两个线程调用的方法都是对静态方法进行加锁==>都是对类对象加锁-->锁的是相同对象-->产生互斥效果.

    取决于任务调度器. 先调度线程1就是 1s之后打印1 ,然后打印2,否则的话先调度线程2就是 打印2 ,1s之后然后打印1

    习题7

    1. class Number7 {
    2. public synchronized static void a(){
    3. System.out.println("1");
    4. }
    5. public synchronized void b(){
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock7 {
    10. public static void main(String[] args) {
    11. Number7 n1 = new Number7();
    12. Number7 n2 = new Number7();
    13. Thread t1 = new Thread(()->{
    14. try {
    15. Thread.sleep(1000);
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. n1.a();
    20. });
    21. Thread t2 = new Thread(()->{
    22. n2.b();
    23. });
    24. t1.start();
    25. t2.start();
    26. }
    27. }

    加锁的对象不一样,线程1调用的方法对类对象加锁,线程2里面利用n2对象调用b方法,对n2对象加锁,所以两个线程是对不同的对象进行加锁->不产生互斥效果.

    所以线程1和线程2是并发执行的,所以是先打印2,一秒后打印1

    习题8

    1. class Number8{
    2. public static synchronized void a() {
    3. System.out.println("1");
    4. }
    5. public static synchronized void b() {
    6. System.out.println("2");
    7. }
    8. }
    9. public class TestBlock8 {
    10. public static void main(String[] args) {
    11. Number8 n1 = new Number8();
    12. Number8 n2 = new Number8();
    13. Thread t1 = new Thread(()->{
    14. try {
    15. Thread.sleep(1000);
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. n1.a();
    20. });
    21. Thread t2 = new Thread(()->{
    22. n2.b();
    23. });
    24. t1.start();
    25. t2.start();
    26. }
    27. }

    虽然是不同的对象调用方法

    但是调用的方法都是对静态方法进行加锁==>都是对类对象加锁-->锁的是相同对象-->产生互斥效果.

    取决于任务调度器. 先调度线程1就是 1s之后打印1 ,然后打印2,否则的话先调度线程2就是 打印2 ,1s之后然后打印1

    总结

    分析这种问题,首先往最根头看起,到底锁的对象是谁,是this还是类对象,还是没有加锁,然后在确定多个对象是否是锁的同一个对象

    • 如果锁的是同一个对象,那么会产生互斥效果,一个线程没有执行完,另外一个线程阻塞等待.
    • 锁的不是同一个对象,那么就不会产生互斥效果,并行的执行
    • 如果没有加锁,那么也是会与其他线程并行的执行

    然后具体情况具体分析,可能分为多种情况-->这种情况就要考虑任务调度器的调度执行了.--->分多种情况去考虑即可

    参考 :

    黑马程序员JUC视频-->哔哩哔哩

  • 相关阅读:
    java计算机毕业设计在线考试系统源程序+mysql+系统+lw文档+远程调试
    [附源码]JAVA毕业设计酒店订房系统(系统+LW)
    如何使用Flask搭建web程序框架并实现无公网IP远程访问本地程序
    js的流程控制
    走进常熟东南相互电子,看AI如何深入产业让工厂更智能
    服务和协议的关系?
    (续)SSM整合之spring笔记(AOP AOP概念及相关术语)(P099)
    五年后端开发,仅考这份面试题和答案,成功涨薪到30k!!!
    Arduino基础知识
    web课程设计网页规划与设计:旅游网页主题网站设计——酒店主题绿色温泉度假酒店网页设计(8页)HTML+CSS+JavaScript
  • 原文地址:https://blog.csdn.net/m0_61210742/article/details/128071979