死锁

1.死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

2.说明:

1)出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
2)我们使用同步时,要避免出现死锁。

1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4 
 5         StringBuffer s1 = new StringBuffer();
 6         StringBuffer s2 = new StringBuffer();
 7 
 8 
 9         new Thread(){
10             @Override
11             public void run() {
12 
13                 synchronized (s1){
14 
15                     s1.append("a");
16                     s2.append("1");
17 
18                     try {
19                         Thread.sleep(100);
20                     } catch (InterruptedException e) {
21                         e.printStackTrace();
22                     }
23 
24                     synchronized (s2){
25                         s1.append("b");
26                         s2.append("2");
27 
28                         System.out.println(s1);
29                         System.out.println(s2);
30                     }
31                 }
32             }
33         }.start();
34 
35 
36         new Thread(new Runnable() {
37             @Override
38             public void run() {
39                 synchronized (s2){
40 
41                     s1.append("c");
42                     s2.append("3");
43 
44                     try {
45                         Thread.sleep(100);
46                     } catch (InterruptedException e) {
47                         e.printStackTrace();
48                     }
49 
50                     synchronized (s1){
51                         s1.append("d");
52                         s2.append("4");
53 
54                         System.out.println(s1);
55                         System.out.println(s2);
56                     }
57                 }
58             }
59         }).start();
60     }
61 }

死锁的演示

1 package com.atguigu.java1;
 2 //死锁的演示
 3 class A {
 4     public synchronized void foo(B b) { //同步监视器:A类的对象:a
 5         System.out.println("当前线程名: " + Thread.currentThread().getName()
 6                 + " 进入了A实例的foo方法"); // ①
 7 //        try {
 8 //            Thread.sleep(200);
 9 //        } catch (InterruptedException ex) {
10 //            ex.printStackTrace();
11 //        }
12         System.out.println("当前线程名: " + Thread.currentThread().getName()
13                 + " 企图调用B实例的last方法"); // ③
14         b.last();
15     }
16 
17     public synchronized void last() {//同步监视器:A类的对象:a
18         System.out.println("进入了A类的last方法内部");
19     }
20 }
21 
22 class B {
23     public synchronized void bar(A a) {//同步监视器:b
24         System.out.println("当前线程名: " + Thread.currentThread().getName()
25                 + " 进入了B实例的bar方法"); // ②
26 //        try {
27 //            Thread.sleep(200);
28 //        } catch (InterruptedException ex) {
29 //            ex.printStackTrace();
30 //        }
31         System.out.println("当前线程名: " + Thread.currentThread().getName()
32                 + " 企图调用A实例的last方法"); // ④
33         a.last();
34     }
35 
36     public synchronized void last() {//同步监视器:b
37         System.out.println("进入了B类的last方法内部");
38     }
39 }
40 
41 public class DeadLock implements Runnable {
42     A a = new A();
43     B b = new B();
44 
45     public void init() {
46         Thread.currentThread().setName("主线程");
47         // 调用a对象的foo方法
48         a.foo(b);
49         System.out.println("进入了主线程之后");
50     }
51 
52     public void run() {
53         Thread.currentThread().setName("副线程");
54         // 调用b对象的bar方法
55         b.bar(a);
56         System.out.println("进入了副线程之后");
57     }
58 
59     public static void main(String[] args) {
60         DeadLock dl = new DeadLock();
61         new Thread(dl).start();
62 
63 
64         dl.init();
65     }
66 }

Lock(锁)

  • 从JDK5.0开始,Java提供了更强大的线程同步机制——通过显示定义同步锁对象来实现同步。同步锁使用Lock对象充当。
  • java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
  • ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。 
1 package com.atguigu.java1;
 2 
 3 import java.util.concurrent.locks.ReentrantLock;
 4 
 5 /**
 6  * 解决线程安全问题的方式三:Lock锁  --- JDK5.0新增
 7  *
 8  * 1. 面试题:synchronized 与 Lock的异同?
 9  *   相同:二者都可以解决线程安全问题
10  *   不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
11  *        Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())
12  *
13  * 2.优先使用顺序:
14  * Lock  同步代码块(已经进入了方法体,分配了相应资源)  同步方法(在方法体之外)
15  *
16  *
17  *  面试题:如何解决线程安全问题?有几种方式
18  */
19 class Window implements Runnable{
20 
21     private int ticket = 100;
22     //1.实例化ReentrantLock
23     private ReentrantLock lock = new ReentrantLock();
24 
25     @Override
26     public void run() {
27         while(true){
28             try{
29 
30                 //2.调用锁定方法lock()
31                 lock.lock();
32 
33                 if(ticket > 0){
34 
35                     try {
36                         Thread.sleep(100);
37                     } catch (InterruptedException e) {
38                         e.printStackTrace();
39                     }
40 
41                     System.out.println(Thread.currentThread().getName() + ":售票,票号为:" + ticket);
42                     ticket--;
43                 }else{
44                     break;
45                 }
46             }finally {
47                 //3.调用解锁方法:unlock()
48                 lock.unlock();
49             }
50 
51         }
52     }
53 }
54 
55 public class LockTest {
56     public static void main(String[] args) {
57         Window w = new Window();
58 
59         Thread t1 = new Thread(w);
60         Thread t2 = new Thread(w);
61         Thread t3 = new Thread(w);
62 
63         t1.setName("窗口1");
64         t2.setName("窗口2");
65         t3.setName("窗口3");
66 
67         t1.start();
68         t2.start();
69         t3.start();
70     }
71 }