死锁
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 }