前言
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();
}
}