006Java多线程006线程八锁案例分析

部分内容来自以下博客:

https://blog.csdn.net/dyt443733328/article/details/80019352

1 多线程的八个案例

通过分析代码,推测打印结果,并运行代码进行验证。

1.1 案例一

一个对象,两个线程调用一个对象的两个同步方法。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number number = new Number();
 4 
 5         new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 number.getOne();
 9             }
10         }).start();
11 
12         new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 number.getTwo();
16             }
17         }).start();
18     }
19 }
20 
21 class Number {
22     public synchronized void getOne() {
23         System.out.println("one");
24     }
25 
26     public synchronized void getTwo() {
27         System.out.println("two");
28     }
29 }
复制代码

运行结果如下:

1 one
2 two

结果分析:

被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行。

1.2 案例二

一个对象,两个线程调用一个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number number = new Number();
 4 
 5         new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 number.getOne();
 9             }
10         }).start();
11 
12         new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 number.getTwo();
16             }
17         }).start();
18     }
19 }
20 
21 class Number {
22     public synchronized void getOne() {
23         try {
24             Thread.sleep(1000);
25         } catch (InterruptedException e) {
26             e.printStackTrace();
27         }
28         System.out.println("one");
29     }
30 
31     public synchronized void getTwo() {
32         System.out.println("two");
33     }
34 }
复制代码

运行结果如下:

1 // 等待一秒。
2 one
3 two

结果说明:

被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。

1.3 案例三

一个对象,两个线程调用一个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待。

对象新增一个普通方法,新增一个线程调用同一对象的普通方法。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number number = new Number();
 4 
 5         new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 number.getOne();
 9             }
10         }).start();
11 
12         new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 number.getTwo();
16             }
17         }).start();
18 
19         new Thread(new Runnable() {
20             @Override
21             public void run() {
22                 number.getThree();
23             }
24         }).start();
25     }
26 }
27 
28 class Number {
29     public synchronized void getOne() {
30         try {
31             Thread.sleep(1000);
32         } catch (InterruptedException e) {
33             e.printStackTrace();
34         }
35         System.out.println("one");
36     }
37 
38     public synchronized void getTwo() {
39         System.out.println("two");
40     }
41 
42     public void getThree() {
43         System.out.println("three");
44     }
45 }
复制代码

运行结果如下:

1 three
2 // 等待一秒。
3 one
4 two

结果说明:

新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。

1.4 案例四

两个对象,两个线程调用两个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number numberOne = new Number();
 4         Number numberTwo = new Number();
 5 
 6         new Thread(new Runnable() {
 7             @Override
 8             public void run() {
 9                 numberOne.getOne();
10             }
11         }).start();
12 
13         new Thread(new Runnable() {
14             @Override
15             public void run() {
16                 numberTwo.getTwo();
17             }
18         }).start();
19     }
20 }
21 
22 class Number {
23     public synchronized void getOne() {
24         try {
25             Thread.sleep(1000);
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29         System.out.println("one");
30     }
31 
32     public synchronized void getTwo() {
33         System.out.println("two");
34     }
35 }
复制代码

运行结果如下:

1 two
2 // 等待一秒。
3 one

结果说明:

被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

1.5 案例五

一个对象,两个线程调用一个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待,并将其设为静态方法。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number number = new Number();
 4 
 5         new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 number.getOne();
 9             }
10         }).start();
11 
12         new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 number.getTwo();
16             }
17         }).start();
18     }
19 }
20 
21 class Number {
22     public static synchronized void getOne() {
23         try {
24             Thread.sleep(1000);
25         } catch (InterruptedException e) {
26             e.printStackTrace();
27         }
28         System.out.println("one");
29     }
30 
31     public synchronized void getTwo() {
32         System.out.println("two");
33     }
34 }
复制代码

运行结果如下:

1 two
2 // 等待一秒。
3 one

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

1.6 案例六

一个对象,两个线程调用一个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待。

将两个同步方法设为静态方法。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number number = new Number();
 4 
 5         new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 number.getOne();
 9             }
10         }).start();
11 
12         new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 number.getTwo();
16             }
17         }).start();
18     }
19 }
20 
21 class Number {
22     public static synchronized void getOne() {
23         try {
24             Thread.sleep(1000);
25         } catch (InterruptedException e) {
26             e.printStackTrace();
27         }
28         System.out.println("one");
29     }
30 
31     public static synchronized void getTwo() {
32         System.out.println("two");
33     }
34 }
复制代码

运行结果如下:

1 // 等待一秒。
2 one
3 two

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法。

1.7 案例七

两个对象,两个线程调用两个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待,并将其设为静态方法。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number numberOne = new Number();
 4         Number numberTwo = new Number();
 5 
 6         new Thread(new Runnable() {
 7             @Override
 8             public void run() {
 9                 numberOne.getOne();
10             }
11         }).start();
12 
13         new Thread(new Runnable() {
14             @Override
15             public void run() {
16                 numberTwo.getTwo();
17             }
18         }).start();
19     }
20 }
21 
22 class Number {
23     public static synchronized void getOne() {
24         try {
25             Thread.sleep(1000);
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29         System.out.println("one");
30     }
31 
32     public synchronized void getTwo() {
33         System.out.println("two");
34     }
35 }
复制代码

运行结果如下:

1 two
2 // 等待一秒。
3 one

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

1.8 案例八

两个对象,两个线程调用两个对象的两个同步方法。

给其中的某个方法增加Thread.sleep()等待。

将两个同步方法设为静态方法。

代码如下:

复制代码
 1 public class Demo {
 2     public static void main(String[] args) {
 3         Number numberOne = new Number();
 4         Number numberTwo = new Number();
 5 
 6         new Thread(new Runnable() {
 7             @Override
 8             public void run() {
 9                 numberOne.getOne();
10             }
11         }).start();
12 
13         new Thread(new Runnable() {
14             @Override
15             public void run() {
16                 numberTwo.getTwo();
17             }
18         }).start();
19     }
20 }
21 
22 class Number {
23     public static synchronized void getOne() {
24         try {
25             Thread.sleep(1000);
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29         System.out.println("one");
30     }
31 
32     public static synchronized void getTwo() {
33         System.out.println("two");
34     }
35 }
复制代码

运行结果如下:

1 // 等待一秒。
2 one
3 two

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,即便用了两个不同的对象调用方法,两个方法用的还是同一个锁,后调用的方法需要等待先调用的方法。

总结

非静态同步方法使用的锁是调用方法的实例对象本身,静态同步方法使用的锁是类对象本身。

因为锁的对象不同,非静态同步方法在执行时不需要等待静态同步方法的执行,静态同步方法在执行时也不需要等待非静态同步方法的执行。

非同步方法不需要锁,非同步方法的执行不受同步方法的影响。

 

posted @   执笔未来  阅读(3465)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示