java基础之互斥锁初解
JDK中常用synchronized用于解决线程安全的问题,那么在JDK1.5的新特性中还提供了一个ReenTrantLock类用于解决线程安全问题,这个类就被称作为互斥锁。
假定我们有三个子线程协同执行任务,那么我们该如何来使用这个互斥锁呢
首先,我们需要建立一个ReenTrantLock对象
//创建互斥锁对象
static ReentrantLock r1 = new ReentrantLock();
既然有三个子线程,那么我们需要提供三个Condition对象,关于这个对象,我们在这里不过多深入,只需要知道Condition对象可以对当前线程执行一些改变线程状态的操作即可,下文会讲到有哪些操作。
//创建3个Condition
static Condition condition1 = r1.newCondition();
static Condition condition2 = r1.newCondition();
static Condition condition3 = r1.newCondition();
到了这一步,准备工作就做好了,我们可以开始创建三个子线程以及他们所执行的方法了
public static void main(String[] args) {
//线程1
new Thread(new Runnable() {
public void run() { try {
//测试方法1
text1();
} catch (Exception e) {
e.printStackTrace();
}}}).start();
//线程2
new Thread(new Runnable() {
public void run() {try {
//测试方法2
text2();
} catch (Exception e) {
e.printStackTrace();
}}}).start();
//线程3
new Thread(new Runnable() {
public void run() {try {
//测试方法3
text3();
} catch (Exception e) {
e.printStackTrace();
}}}).start();
}
测试方法如下
public static void text1() throws Exception {
r1.lock(); //加锁
System.out.println("text1");
Thread.sleep(1000);
condition1.await(); //让当前线程等待,且当前线程会带上condition1的标识,该标识可用来通过condition1唤醒线程,即进入阻塞状态
System.out.println("text1唤醒后");
condition2.signal(); //唤醒标识为condition2的阻塞状态的线程
r1.unlock(); //解锁
}
public static void text2() throws Exception {
r1.lock();
System.out.println("text2");
Thread.sleep(1000);
condition2.await(); //让当前线程等待,且当前线程会带上condition2的标识,该标识可用来通过condition2唤醒线程,即进入阻塞状态
System.out.println("text2唤醒后");
condition3.signal(); //唤醒标识为condition3的阻塞状态的线程
r1.unlock();
}
public static void text3() throws Exception {
r1.lock();
System.out.println("text3");
Thread.sleep(1000);
condition1.signal(); //唤醒标识为condition1的阻塞状态的线程
condition3.await(); //让当前线程等待,且当前线程会带上condition3的标识,该标识可用来通过condition3唤醒线程,即进入阻塞状态
System.out.println("text3唤醒后");
r1.unlock();
}
从上面的代码中我们可以看到,
其一,位于lock()和unlock()方法之间的代码既是同步代码部分。
其二,ReenTrantLock的对象r1的lock()方法可以开启互斥锁,并且该锁的状态由r1来维护,即r1开启的锁只能由r1来解锁。
其三,Condition对象可以通过await()方法将当前线程设为阻塞状态,同时会解开锁,并且被设为阻塞状态的线程会被带上condition对象标识,当执行condition对象 . signal()来唤醒线程时,就会根据对象标识来选择唤醒哪个线程。
其四,ReenTrantLock的unlock()方法用来解锁
最终运行结果是
text1
text2
text3
text1唤醒后
text2唤醒后
text3唤醒后
通过结果可以看到,三个线程实现了协同工作。
本次互斥锁的讲解到此为止,目前的讲解还只停留在表面,有兴趣的朋友可以自己去深入了解下。