多線程--Lock鎖

Lock鎖

在 jdk1.5 之後,併發包中新增了 Lock 接口(以及相關實現類)用來實現鎖功能,Lock 接口提供了與 synchronized 關鍵字類似的同步功能,但需要在使用時手動獲取鎖和釋放鎖,且在使用上比synchronized更加靈活。

1、使用ReentrantLock實現同步

在這裏插入圖片描述

案例:

package com.yxl.demo.ThreadTest;

public class test5 {

    public static void main(String[] args) {

        TestDemo thread = new TestDemo();
        Thread t1 = new Thread(thread,"窗口一");
        Thread t2 = new Thread(thread,"窗口二");
        t1.start();
        t2.start();
    }
}

class TestDemo implements Runnable{
    //共享的火車票變量
    private  int count = 100;

    //重寫run方法
    @Override
    public void run() {
        while (count > 0){
            try {
            	//休眠一下 方便出現併發問題
                Thread.sleep(50);
            }catch (Exception e){
                e.getMessage();
            }
            sale();
        }
    }
    //賣票
    public void sale(){
        if(count > 0){
            System.out.println(Thread.currentThread().getName() +"出售 :" +(100 -  count + 1));
            count--;
        }
    }
}

運行結果如下:會發現出現賣重複票的問題

除了 內置鎖(Synchronized)解決方案,我們可以使用 Lock鎖解決

synchronized的缺陷
synchronized是Java中的一個關鍵字。

我們知道如果一段代碼被synchronized修飾了,當一個線程獲取了對應的鎖,並執行該代碼塊的時候,其他的線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這裏獲鎖的線程釋放鎖有兩種情況:

  1. 獲取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的佔有;

  2. 線程執行發生異常,此時JVM會讓線程自動釋放鎖。

如果這個獲取鎖的線程由於I/O或者其他原因(如調用sleep方法)被阻塞了,但是有沒有釋放鎖,其他線程便只能乾巴巴地等待,這會很影響執行效率。

因此就需要一種機制可以不讓等待的線程一直無限期地等待下去(如只等待一定的時間或者能夠響應中斷),通過Lock就可以辦到。

再如:當有多個線程讀取文件時,讀操作和寫操作會發生衝突,寫操作和寫操作會發生衝突,但是讀操作和讀操作不會發生衝突。

如果此時採用synchronized關鍵字就會出現一個問題:如果多個線程只是進行讀操作,所以當一個線程進行讀操作時,其他的線程只能等待無法進行讀操作。

因此就需要 一種機制使得多個線程都只是進行讀操作時,線程之間不會發生衝突,通過Lock就可以辦到。

另外,通過Lock可以知道線程有沒有成功獲取鎖,這是synchronized無法辦到的。

注意:

  1. Lock不是Java語言內置的,synchronized是Java語言的關鍵字,因此是內置特性,Lock是一個類(接口),通過這個類可以實現同步訪問;

  2. 使用synchronized不需要用戶手動去釋放鎖,當synchronized方法或代碼塊執行完後,系統會自動讓線程釋放對鎖的佔用;而Lock則必須要用戶手動釋放鎖,如果沒有主動釋放,就有可能導致出現死鎖。

**使用Lock鎖案例 **

package com.yxl.demo.ThreadTest;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class test5 {

    public static void main(String[] args) throws InterruptedException {

        TestDemo thread = new TestDemo();
        Thread t1 = new Thread(thread,"窗口一");
        Thread t2 = new Thread(thread,"窗口二");
        t1.start();
        t2.start();
    }
}

class TestDemo implements Runnable{
    //共享的火車票變量
    private  int count = 100;

    //重寫run方法
    @Override
    public void run() {
               while (count > 0) {
                       sale();
           }

        }

    public  void sale() {
        Lock lock  = new ReentrantLock();
        lock.lock();
        try {
            if (count > 0) {
                System.out.println(Thread.currentThread().getName() + "出售 :" + (100 - count + 1));
                count--;
            }
        }catch (Exception e){

        }finally {
            //一定在finally中釋放鎖
            lock.unlock();
        }

    }
}








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章