使用ReentrantLock,最大的感触就是,一定要严格按照使用规范去写,否则各种多线程问题让人防不胜防。
大概几点吧:
1、无论是ReentrantLock还是Condition都是为了锁资源而存在的,没有资源的话,这些东西就没有意义。
2、ReentrantLock是为了保证操作资源的互斥性,Condition是为了消除等待资源的时间浪费。
3、ReentrantLock一定要lock和unlock配对出现,并且一定要保证不管走任何代码分支,都要有unlock操作。(写示例中,就在while循环内部写了lock,在外部finally写了unlock,结果死锁了)
4、必须是先增加资源,然后才释放出signal信号。
小小示例,随意看看吧~~
package lock;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestCondition {
static ReentrantLock lock = new ReentrantLock();
static int[] resource = new int[] { 0, 0, 0, 0, 0 };
public static void main(String[] args) {
// test1();
test2();
}
private static void test1() {
int[][][] testcase1 = new int[][][] {
new int[][] { new int[] { 0, 1, 2, 3 }, new int[] { 4 } },
new int[][] { new int[] { 0, 1, 2 }, new int[] { 3, 4 } },
new int[][] { new int[] { 0, 1 }, new int[] { 2, 3, 4 } },
new int[][] { new int[] { 0 }, new int[] { 1, 2, 3, 4 } },
new int[][] { new int[] {}, new int[] { 0 } } };
test(testcase1);
}
private static void test2() {
int[][][] testcase2 = new int[][][] {
new int[][] { new int[] { 0 }, new int[] { 1 } },
new int[][] { new int[] { 1 }, new int[] { 2 } },
new int[][] { new int[] { 2 }, new int[] { 3 } },
new int[][] { new int[] { 3 }, new int[] { 4 } },
new int[][] { new int[] { 4 }, new int[] { 0 } } };
Condition start = test(testcase2)[0];
lock.lock();
resource[0]++;
start.signal();
lock.unlock();
}
static Condition[] test(int[][][] testcase) {
Condition[] conditions = new Condition[resource.length];
for (int i = 0; i < conditions.length; i++) {
conditions[i] = lock.newCondition();
}
List<Thread> list = new LinkedList<Thread>();
for (int[][] worker : testcase) {
list.add(new Thread(new Runit(conditions, worker[0], worker[1])));
}
int i = 0;
for (Thread t : list) {
t.setName("t" + i++);
t.start();
}
return conditions;
}
static class Runit implements Runnable {
Condition[] cons;
int[] waits;
int[] signals;
/**
* 模拟生产线
*
* @param cons 对应resource的Condition数组
* @param wait 该生产线的原料
* @param signal 该生产线的产出
*/
public Runit(Condition[] cons, int[] wait, int[] signal) {
this.cons = cons;
this.waits = wait;
this.signals = signal;
}
@Override
public void run() {
while (true) {
try {
sleep();
lock.lock(); // 锁住全部资源,不允许其他线程操作resource
if (waits != null) {
for (int c : waits) {
if (resource[c] <= 0) {
cons[c].await(); // 发现某个资源欠缺,释放锁,等待唤醒重新竞争锁
}
resource[c]--; // 消耗资源
}
}
if (signals != null) {
for (int c : signals) {
resource[c]++; // 产出资源
System.out.println("Thread "
+ Thread.currentThread().getName()
+ " make a product -- " + c);
cons[c].signal(); // 通知本生产线某产品制成
}
}
} catch (Exception e) {
System.out.println(e);
} finally {
lock.unlock(); // 释放资源锁,允许其他线程竞争resource处理资格
}
}
}
private void sleep() throws InterruptedException {
Random rad = new Random();
int r = rad.nextInt(4000);
if (r < 0) {
r = -r;
}
Thread.sleep(1000 + r);
}
}
}