有这么个简单的实际问题,让A线程打印”A”,让B线程打印”B”,让C线程打印”C”,每个线程各执行五次,要实现ABC线程依次执行。
下面用传统的Synchronized和wait,notifyAll来实现这个需求:
/**
* 用synchronized(互斥)和wait notify(同步)来实现 线程的同步
* @author HKL
*
*/
public class Test3 {
String type = "A";
;
public static void main(String[] args) {
final Test3 t = new Test3();
final int NUM = 5;
new Thread(){
public void run() {
for(int i = 0 ; i <NUM; i++ ){
t.A(i);
}
};
}.start();
new Thread(){
public void run() {
for(int i = 0 ; i <NUM; i++ ){
t.B(i);
}
};
}.start();
new Thread(){
public void run() {
for(int i = 0 ; i <NUM; i++ ){
t.C(i);
}
};
}.start();
}
public synchronized void A(int i ) {
while (type != "A") {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 正在打印A--i="+i);
type = "B";
notifyAll();
}
public synchronized void B(int i) {
while (type != "B") {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 正在打印B--i="+i);
type = "C";
notifyAll();
}
public synchronized void C(int i) {
while (type != "C") {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 正在打印C--i="+i);
type = "A";
notifyAll();
}
}
运行结果:
Thread-0 正在打印A--i=0
Thread-1 正在打印B--i=0
Thread-2 正在打印C--i=0
Thread-0 正在打印A--i=1
Thread-1 正在打印B--i=1
Thread-2 正在打印C--i=1
Thread-0 正在打印A--i=2
Thread-1 正在打印B--i=2
Thread-2 正在打印C--i=2
Thread-0 正在打印A--i=3
Thread-1 正在打印B--i=3
Thread-2 正在打印C--i=3
Thread-0 正在打印A--i=4
Thread-1 正在打印B--i=4
Thread-2 正在打印C--i=4
这里之所以用notifyAll()而不是用notify()来唤醒线程,是因为notify只能随机唤醒一个线程,容易造成死锁。大家可以尝试用notify换成notifyAll测试一下。哪怕只有两个线程协作也可能出现死锁的问题。
但是,我们在运行完线程A的时候只想唤醒线程B呢?这时候就得用上java Concurrent包下的Condition和Lock了。
直接上代码:
public class Test1 {
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
private Condition conditionC = lock.newCondition();
private String type = "A";
public static void main(String[] args) {
final Test1 test = new Test1();
final int NUM = 5;
new Thread("Thread-A") {
public void run() {
for (int i = 0; i < NUM; i++) {
test.A();
}
};
}.start();
new Thread("Thread-B") {
public void run() {
for (int i = 0; i < NUM; i++) {
test.B();
}
};
}.start();
new Thread("Thread-C") {
public void run() {
for (int i = 0; i < NUM; i++) {
test.C();
}
};
}.start();
}
public void A() {
lock.lock();
try {
while (type != "A") {
try {
conditionA.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 正在打印A");
type = "B";
conditionB.signal();
} finally {
lock.unlock();
}
}
public void B() {
lock.lock();
try {
while (type != "B") {
try {
conditionB.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 正在打印B");
type = "C";
conditionC.signal();
} finally {
lock.unlock();
}
}
public void C() {
lock.lock();
try {
while (type != "C") {
try {
conditionC.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 正在打印C");
type = "A";
conditionA.signal();
} finally {
lock.unlock();
}
}
}
运行结果:
Thread-A 正在打印A
Thread-B 正在打印B
Thread-C 正在打印C
Thread-A 正在打印A
Thread-B 正在打印B
Thread-C 正在打印C
Thread-A 正在打印A
Thread-B 正在打印B
Thread-C 正在打印C
Thread-A 正在打印A
Thread-B 正在打印B
Thread-C 正在打印C
Thread-A 正在打印A
Thread-B 正在打印B
Thread-C 正在打印C
这样子我们在多线程协作的过程中就可以指定唤醒哪一个线程了,具有更强的灵活性。