1. 程式人生 > >jdk鎖的使用

jdk鎖的使用

ReentrantLock
public class JdkLockTest implements Runnable{

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    private static int i = 0;

    public static void main(String[] args) {
        JdkLockTest jdkLockTest = new JdkLockTest();
        Thread t1 = new Thread(jdkLockTest);
        Thread t2 = new Thread(jdkLockTest);
        Thread t3 = new Thread(jdkLockTest);
        t1.start();
        t2.start();
        t3.start();
    }

    @Override
    public void run(){
        lock .lock();

        try {
            System.out.println("開始等待2s");
            condition.await(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("ThreadName=" + Thread.currentThread().getName());
        for(int j=0; j<1000000; j++){
            i++;
        }
        System.out.println("i = " + i);
        lock.unlock();
    }
}

ReentrantLock其他方法

  • getHoldCount() 查詢當前執行緒保持此鎖的次數,也就是執行此執行緒執行lock方法的次數
  • getQueueLength()返回正等待獲取此鎖的執行緒估計數,比如啟動10個執行緒,1個執行緒獲得鎖,此時返回的是9
  • getWaitQueueLength(Condition condition)返回等待與此鎖相關的給定條件的執行緒估計數。比如10個執行緒,用同一個condition物件,並且此時這10個執行緒都執行了condition物件的await方法,那麼此時執行此方法返回10
  • hasWaiters(Condition condition)查詢是否有執行緒等待與此鎖有關的給定條件(condition),對於指定contidion物件,有多少執行緒執行了condition.await方法
  • hasQueuedThread(Thread thread)查詢給定執行緒是否等待獲取此鎖
  • hasQueuedThreads()是否有執行緒等待此鎖
  • isFair()該鎖是否公平鎖
  • isHeldByCurrentThread() 當前執行緒是否保持鎖鎖定,執行緒的執行lock方法的前後分別是false和true
  • isLock()此鎖是否有任意執行緒佔用
  • lockInterruptibly()如果當前執行緒未被中斷,獲取鎖
  • tryLock()嘗試獲得鎖,僅在呼叫時鎖未被執行緒佔用,獲得鎖
  • tryLock(long timeout TimeUnit unit)如果鎖在給定等待時間內沒有被另一個執行緒保持,則獲取該鎖

 

 

Semaphore 
public class SemaphoreTest {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for(int i=0; i<10; i++){
            executorService.execute(new Test(semaphore));
        }
        executorService.shutdown();
    }


}

class Test implements Runnable{

    private Semaphore semaphore;
    private int i=0;

    public Test(){}
    public Test(Semaphore semaphore){
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire();
            for(int j=0; j<1000000; j++){
                i++;
            }
            System.out.println("i = " + i);
            System.out.println("當前執行緒=====》"+ Thread.currentThread().getName());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

其他方法,(摘自網路)

Semaphore的方法如下:

——Semaphore(permits)  初始化許可證數量的建構函式

——Semaphore(permits,fair)  初始化許可證數量和是否公平模式的建構函式

——isFair()  是否公平模式FIFO

——availablePermits()  獲取當前可用的許可證數量

——acquire()

當前執行緒嘗試去阻塞的獲取1個許可證。

此過程是阻塞的,它會一直等待許可證,直到發生以下任意一件事:

當前執行緒獲取了1個可用的許可證,則會停止等待,繼續執行。
當前執行緒被中斷,則會丟擲InterruptedException異常,並停止等待,繼續執行。
——acquire(permits)

當前執行緒嘗試去阻塞的獲取permits個許可證。

此過程是阻塞的,它會一直等待許可證,直到發生以下任意一件事:

當前執行緒獲取了n個可用的許可證,則會停止等待,繼續執行。
當前執行緒被中斷,則會丟擲InterruptedException異常,並停止等待,繼續執行。

——acquierUninterruptibly()

當前執行緒嘗試去阻塞的獲取1個許可證(不可中斷的)。

此過程是阻塞的,它會一直等待許可證,直到發生以下任意一件事:

當前執行緒獲取了1個可用的許可證,則會停止等待,繼續執行。
——acquireUninterruptibly(permits)

當前執行緒嘗試去阻塞的獲取permits個許可證。

此過程是阻塞的,它會一直等待許可證,直到發生以下任意一件事:

當前執行緒獲取了n個可用的許可證,則會停止等待,繼續執行。
——tryAcquire()

當前執行緒嘗試去獲取1個許可證。

此過程是非阻塞的,它只是在方法呼叫時進行一次嘗試。

如果當前執行緒獲取了1個可用的許可證,則會停止等待,繼續執行,並返回true。

如果當前執行緒沒有獲得這個許可證,也會停止等待,繼續執行,並返回false。

——tryAcquire(permits)

當前執行緒嘗試去獲取permits個許可證。

此過程是非阻塞的,它只是在方法呼叫時進行一次嘗試。

如果當前執行緒獲取了permits個可用的許可證,則會停止等待,繼續執行,並返回true。

如果當前執行緒沒有獲得permits個許可證,也會停止等待,繼續執行,並返回false。

——tryAcquire(timeout,TimeUnit)

當前執行緒在限定時間內,阻塞的嘗試去獲取1個許可證。

此過程是阻塞的,它會一直等待許可證,直到發生以下任意一件事:

當前執行緒獲取了可用的許可證,則會停止等待,繼續執行,並返回true。
當前執行緒等待時間timeout超時,則會停止等待,繼續執行,並返回false。
當前執行緒在timeout時間內被中斷,則會丟擲InterruptedException一次,並停止等待,繼續執行。
——tryAcquire(permits,timeout,TimeUnit)

當前執行緒在限定時間內,阻塞的嘗試去獲取permits個許可證。

此過程是阻塞的,它會一直等待許可證,直到發生以下任意一件事:

當前執行緒獲取了可用的permits個許可證,則會停止等待,繼續執行,並返回true。
當前執行緒等待時間timeout超時,則會停止等待,繼續執行,並返回false。
當前執行緒在timeout時間內被中斷,則會丟擲InterruptedException一次,並停止等待,繼續執行。
——release() 當前執行緒釋放1個可用的許可證。

——release(permits) 當前執行緒釋放permits個可用的許可證。

——drainPermits() 當前執行緒獲得剩餘的所有可用許可證。

——hasQueuedThreads() 判斷當前Semaphore物件上是否存在正在等待許可證的執行緒。

——getQueueLength() 獲取當前Semaphore物件上是正在等待許可證的執行緒數量。

 

ReadWriteLock   當寫操作時,其他執行緒無法讀取或寫入資料,而當讀操作時,其它執行緒無法寫入資料,但卻可以讀取資料 。

public class ReadWriteLockTest {

    public static void main(String[] args) {
        TestReadWrite testReadWrite = new TestReadWrite();

        for(int i=0; i<10; i++){
            new Thread(testReadWrite::read).start();
        }

        for(int j=0; j<10; j++) {
            new Thread(() -> testReadWrite.write("你好")).start();
        }
    }

}

class TestReadWrite{
    private String data;
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void read(){
        readWriteLock.readLock().lock();//執行緒只能讀,不能寫
        System.out.println(Thread.currentThread().getName() + "讀取資料========");
        try {
            Thread.sleep((long)(Math.random()*1000));
            System.out.println(Thread.currentThread().getName() + "讀取完資料 :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

    public void write(String data){
        readWriteLock.writeLock().lock();//不允許其他執行緒讀寫操作
        System.out.println(Thread.currentThread().getName() + "寫資料========");
        try {
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data;
            System.out.println(Thread.currentThread().getName() + "寫資料完成 ==" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }

    }
}
CountDownLacth

某一執行緒在開始執行前等待n個執行緒執行完畢。將CountDownLatch的計數器初始化為n new CountDownLatch(n) ,每當一個任務執行緒執行完畢,就將計數器減1 countdownlatch.countDown(),當計數器的值變為0時,在CountDownLatch上 await() 的執行緒就會被喚醒。

public class CountDownLacthTest {

    public static void main(String[] args) {
        final CountDownLatch countDown = new CountDownLatch(2);

        Thread t1 = new Thread(() -> {
            System.out.println("執行緒t1開始執行-------------");
            try {
                System.out.println("執行緒t1等待其他執行緒-------------");
                countDown.await();
                System.out.println("執行緒t1繼續執行-------------");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        Thread t2 = new Thread(() -> {
            try {
                System.out.println("執行緒t2開始執行-------------");
                Thread.sleep((long) (Math.random()*1000));
                System.out.println("執行緒t2執行完畢-------------");
                countDown.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t2");

        Thread t3 = new Thread(() -> {
            try {
                System.out.println("執行緒t3開始執行-------------");
                Thread.sleep((long) (Math.random()*1000));
                System.out.println("執行緒t3執行完畢-------------");
                countDown.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t3");

        t1.start();
        t2.start();
        t3.start();

    }
}

CyclicBarrier   注意:當執行緒數和parties不一致的時候有可能發生阻塞問題!最後剩下的執行緒數不足parties,無法繼續執行下去

public class CyclicBarrierTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final CyclicBarrier cb = new CyclicBarrier(3);//當有3個執行緒到達時,共同執行
//final CyclicBarrier cb = new CyclicBarrier(3, () -> System.out.println("********我最先執行***********"));
        for (int i = 0; i < 3; i++) {
            Runnable runnable = () -> {
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("執行緒" + Thread.currentThread().getName() +
                            "即將到達集合地點1,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候");
                    cb.await();//到此如果沒有達到公共屏障點,則該執行緒處於等待狀態,如果達到公共屏障點則所有處於等待的執行緒都繼續往下執行

                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("執行緒" + Thread.currentThread().getName() +
                            "即將到達集合地點2,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候");
                    cb.await();
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("執行緒" + Thread.currentThread().getName() +
                            "即將到達集合地點3,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候");
                    cb.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
            service.execute(runnable);
        }
        service.shutdown();
    }
}