JAVA併發之多線程基礎(2)

NO IMAGE

JAVA併發之多線程基礎(2)

除了我們經常用的synchronized關鍵字(結合Objectwait()notify()使用)之外,還有對應的上篇文章講到的方法JAVA併發之多線程基礎(1)之外,我們日常中使用到最多的也就是JUC下面對應的類與方法。

ReentrantLock

ReentrantLock在JDK1.5之前比Synchronized性能好許多,在之後Synchronized也進行了修改,使得當下兩個在對於線程方面性能相差無幾。但是ReentrantLock的功能更加豐富,它的特點有:可重入、可中斷、可限時、公平鎖。

package com.montos.lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int k = 0;
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
lock.lock();
k++;
}
for (int i = 0; i < 1000; i++) {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockDemo demo = new ReentrantLockDemo();
Thread t1 = new Thread(demo);
Thread t2 = new Thread(demo);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(k);
}
}
  1. 通過這個小的demo可以看到控制檯中無論如何執行,輸出的值都是2000。這裡面就體現了可重入(對於同一把鎖進行加鎖和釋放鎖)的特點。

  2. 可中斷則在lockInterruptibly()這個方法上進行體現。

public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

使用這個方法就可以在加鎖的過程中進行中斷,用來保證程序的正常進行下去,避免死鎖一直阻塞程序運行。通過上面的方法進行查看底層調用的:

    //以獨佔模式獲取,如果中斷將中止。
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted()) //測試當前線程是否已中斷
throw new InterruptedException();
if (!tryAcquire(arg)) //嘗試獲取arg次鎖操作
doAcquireInterruptibly(arg);//以獨佔中斷模式獲取鎖操作
}
  1. 可限時操作在tryLock(long timeout, TimeUnit unit)方法中體現,目的主要是防止死鎖的發生。
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

在使用這個的時候,也要注意在finally中也要釋放鎖,當然在釋放之前先判斷當前當前線程是否持有鎖操作lock.isHeldByCurrentThread()

  1. 公平鎖則在ReentrantLock的構造函數中體現出來。所謂公平鎖與非公平鎖就是線程先來先到和先來不一定拿到鎖的情況的。
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

當然非公平鎖的性能要比公平鎖的性能好很多,公平鎖裡面還要維護一個隊列(AQS)來進行操控公平性。所以說一般沒有特殊要求的情況下,默認使用非公平的鎖就可以。

Condition

上面講完重入鎖之後,這裡在講解一個與重入鎖密切相關的類。他與重入鎖之間的關係猶如synchronizedObjectwait()notify()一樣。也就是說在使用它的情況也要獲得當前的鎖,才可以進行下面的操作。

package com.montos.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockCondition implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
@Override
public void run() {
try {
lock.lock();//拿到對應鎖
condition.await();
System.out.println("wait is end,going down");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockCondition conditions = new ReentrantLockCondition();
Thread thread = new Thread(conditions);
thread.start();
Thread.sleep(2000);
lock.lock();
condition.signal();//只有拿到對應鎖上面的監視器才可以執行
lock.unlock();
}
}

這上面的Condition的用法相當於Object裡面的兩個方法一樣。總體來說使用重入鎖也是看業務場景情況下使用,如果想要上面特點的鎖方法,那麼使用重入鎖就是很好的。不然的話使用synchronized關鍵字就可以完成大多數的業務場景了。

相關文章

JAVA併發之多線程基礎(6)

JAVA併發之多線程基礎(5)

JAVA併發之多線程基礎(4)

JAVA併發之多線程基礎(3)