day20Java-常用对象Thread-Lock锁以及死锁

Lock锁

java.util.concurrent.locks

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。

1
2
3
4
Lock:
        void lock(): 获取锁。
        void unlock():释放锁。  
ReentrantLock是Lock的实现类。

代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SellTicketDemo {

    public static void main(String[] args) {
        //创建线程对象
        SellTicket st = new SellTicket();

        //创建Thread对象
        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");

        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

自定义类实现Runnable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class SellTicket implements Runnable {
    //定义100张票
    private int ticket = 100;
    //创建Lock锁对象
    Lock lock = new ReentrantLock();

    //Lock锁写法
    @Override
    public void run() {
        while (true) {
            //开
            lock.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");

            }
            //关
            lock.unlock();
        }
    }
   
    //以前的写法
    /*@Override
    public void run() {
        while (true){
            synchronized (this) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
                }
            }
        }
    }*/
}

结果:

1
2
3
4
5
6
7
8
9
10
窗口1正在出售第10张票
窗口1正在出售第9张票
窗口3正在出售第8张票
窗口3正在出售第7张票
窗口3正在出售第6张票
窗口3正在出售第5张票
窗口3正在出售第4张票
窗口3正在出售第3张票
窗口3正在出售第2张票
窗口3正在出售第1张票

死锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
同步的弊端:
        A:效率低
        B:容易产生死锁

死锁:
        两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。

举例:
        中国人,美国人吃饭案例。
        正常情况:
            中国人:筷子两支
            美国人:刀和叉
        现在:
            中国人:筷子1支,刀一把
            美国人:筷子1支,叉一把

代码演示

1
2
3
4
5
6
7
8
9
10
11
12
public class DieLockDemo {
    public static void main(String[] args) {

        //创建线程对象
        DieLock dl1 = new DieLock(true);
        DieLock dl2 = new DieLock(false);

        //启动线程
        dl1.start();
        dl2.start();
    }
}

死锁代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DieLock extends Thread{

    private boolean flag;

    public DieLock(boolean flag) {
        this.flag = flag;
    }

    //死锁代码演示
    @Override
    public void run() {
        if (flag) {
            synchronized (MyLock.objA) { //线程tl1,进来关闭锁。
                System.out.println("if objA");
                synchronized (MyLock.objB) {//因为tl2锁已经关闭了,所以在等tl2执行完开锁。
                    System.out.println("if objB");                    
                }                                                                          
            }                                                 //出现了相互等待的情况,即死锁。                  
        } else {
            synchronized (MyLock.objB) {//线程tl2,进来关闭锁。
                System.out.println("else objB");
                synchronized (MyLock.objA) {//因为tl1锁已经关闭了,所以在等tl1执行完开锁。
                    System.out.println("else objA");
                }
            }
        }
    }
}

定义两把锁

1
2
3
4
public class MyLock {
    public static final Object objA = new Object();
    public static final Object objB=  new Object();
}

结果:出现死锁(是有可能出现)

1
2
else objB
if objA