前言
java中多線程編碼中除了synchronized 關鍵詞以外,就是使用lock接口實現鎖。本次就講一相關實現
ReentrantLock
ReentrantLock的第一個例子可以簡單的用於一個鎖。鎖定一個變量,只有當線程獲得鎖的時候纔可以對變量進行修改。下面的代碼舉例的了我鎖住了一個靜態變量。即使多線程修改,也不會出現多線程問題。相反如果去掉鎖,會發現變量的修改會出現多線程問題
import java.util.concurrent.locks.ReentrantLock;
public class Test20 extends Thread{
public static int result = 0;
public static class Test extends Thread{
private ReentrantLock lock;
public Test(ReentrantLock lock) {
this.lock = lock;
}
public void run(){
while (true){
//可以去除lock和unlock發現發生了線程不安全
lock.lock();
result++;
System.out.println("thread"+Thread.currentThread().getName()+",result"+result);
lock.unlock();
}
}
}
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock(true);
Test test1 = new Test(lock);
Test test2 = new Test(lock);
Test test3 = new Test(lock);
test1.setName("test1");
test2.setName("test2");
test3.setName("test3");
test1.start();
test2.start();
test3.start();
}
}
trylock()可以在一段時間內獲得一個鎖,可以看到獲得鎖的線程begin了,然後看到try失敗的線程也迅速進入,進行了begin。表明trylock()成功了。
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class Test21 extends Thread{
private ReentrantLock lock;
public Test21(ReentrantLock lock) {
this.lock = lock;
}
public void run(){
while (true){
boolean locked = false;
try {
locked = lock.tryLock(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread"+Thread.currentThread().getName()+"begin");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread"+Thread.currentThread().getName()+"next");
if(locked){
lock.unlock();
}
}
}
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock(true);
Test21 test1 = new Test21(lock);
Test21 test2 = new Test21(lock);
Test21 test3 = new Test21(lock);
test1.setName("test1");
test2.setName("test2");
test3.setName("test3");
test1.start();
test2.start();
test3.start();
}
}
ReentrantReadWriteLock
可以看到寫了2個類,一個進行寫,一個進行讀,可以看到每次讀線程都會同時進行,寫線程是單獨進行的。交替進行,在寫線程進行寫的時候會卡住讀線程的相關操作,但是讀線程是可以併發進行的。各個讀之間不受影響
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test22 extends Thread{
public static int result = 0;
static class Test22A extends Thread{
private ReentrantReadWriteLock lock;
public Test22A(ReentrantReadWriteLock lock) {
this.lock = lock;
}
public void run(){
while (true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.writeLock().lock();
System.out.println("result change");
result = result+1;
System.out.println("thread:"+Thread.currentThread().getName()+",result:"+result);
lock.writeLock().unlock();
}
}
}
static class Test22B extends Thread {
private ReentrantReadWriteLock lock;
public Test22B(ReentrantReadWriteLock lock) {
this.lock = lock;
}
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.readLock().lock();
System.out.println("thread:" + Thread.currentThread().getName() + ",result:" + result);
lock.readLock().unlock();
}
}
}
public static void main(String[] args) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
Test22B b1 = new Test22B(lock);
Test22B b2 = new Test22B(lock);
Test22B b3 = new Test22B(lock);
Test22B b4 = new Test22B(lock);
Test22A a1 = new Test22A(lock);
Test22A a2 = new Test22A(lock);
b1.setName("b1");
b2.setName("b2");
b3.setName("b3");
b4.setName("b4");
a1.setName("a1");
a2.setName("a2");
a1.start();
a2.start();
b1.start();
b2.start();
b3.start();
b4.start();
}
}