天天看點

多線程--Lock鎖Lock鎖

@[toc]

Lock鎖

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

1、使用ReentrantLock實作同步

多線程--Lock鎖Lock鎖

案例:

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--;
        }
    }
}
           

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

多線程--Lock鎖Lock鎖

除了 内置鎖(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();
        }
    }
}           

lock.lock() 擷取鎖

lock.unlock() 釋放鎖,但要在 finally中使用

lock.trylock() 擷取鎖 ,也要結合 try catch 一起使用
上一篇: JVM--入門篇