6.JUC執行緒高階-Lock同步鎖

潘天涯發表於2018-09-04

1. 解決多執行緒安全問題的方式:

  1. 同步程式碼塊
synchronized(this) {
}
  1. 同步方法
 public synchronized void method() {
 }

public static synchronized void method() {
 }

JDK1.5之前才使用上述兩種方式藉助於:synchronized 隱式鎖。之後出現一個新的顯示同步鎖

  1. 同步鎖 Lock 顯示鎖
    顯示鎖:必須通過 lock() 方法上鎖,通過 unlock() 方法進行釋放鎖
    此種方式是一種更加靈活更加高階處理執行緒安全問題的方式,但它也存在一定的不足,需要手動(finally)釋放鎖。

下面使用賣票例項來模擬 Lock鎖的使用:


package com.pyy.juc;


public class TestLock {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        new Thread(ticket, "1號視窗").start();
        new Thread(ticket, "2號視窗").start();
        new Thread(ticket, "3號視窗").start();
    }

}

class Ticket implements Runnable {

    private int tick = 100;

    @Override
    public void run() {
        while(true) {
            if(tick > 0) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 完成售票,餘票為:" + --tick);
            }
        }
    }
}

結果: 出現多個視窗賣同一張票的情況

...
2號視窗 完成售票,餘票為:24
1號視窗 完成售票,餘票為:23
2號視窗 完成售票,餘票為:22
3號視窗 完成售票,餘票為:22
1號視窗 完成售票,餘票為:21
3號視窗 完成售票,餘票為:20
2號視窗 完成售票,餘票為:19
...

下面使用同步鎖Lock- ReenTrantLock實現:


package com.pyy.juc;


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

public class TestLock {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        new Thread(ticket, "1號視窗").start();
        new Thread(ticket, "2號視窗").start();
        new Thread(ticket, "3號視窗").start();
    }

}

class Ticket implements Runnable {

    private int tick = 100;

    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true) {

            lock.lock();// 加鎖
            
            try {
                if(tick > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " 完成售票,餘票為:" + --tick);
                }
            } finally {
                lock.unlock();// 釋放鎖
            }
        }
    }
}

結果不會出現執行緒安全問題。


相關文章