下面的程序是用来让3个线程一次执行的程序。原来的题目是建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。我这里进行了一点点简化,只让3个线程打印一次ABC。
package com.exinglo.sync;
/**
*
* @author exinglo
*
*
*/
public class ABCPrinter {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final MyThread mth = new MyThread();
new Thread() {
@Override
public void run() {
mth.printA();
}
}.start();
new Thread() {
@Override
public void run() {
mth.printB();
}
}.start();
new Thread() {
@Override
public void run() {
mth.printC();
}
}.start();
mth.startRun();
}
static class MyThread {
private int turn = 0;
public void startRun() {
synchronized (this) {
this.turn = 1;
this.notifyAll();
}
}
public void printA() {
// synchronized (this) {
// while (turn == 1) {
// System.out.println("A");
// turn = 2;
//
// }
// try {
// this.wait();
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// this.notifyAll();
// }
synchronized (this) {
while (turn != 1) {
try {
System.out.println(this.turn);
System.out.println("A");
this.wait();
this.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("A:" + this.turn);
this.turn = 2;
this.notifyAll();
}
}
public void printB() {
synchronized (this) {
while (turn != 2) {
try {
System.out.println(this.turn);
System.out.println("B");
this.wait();
this.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("B:" + this.turn);
this.turn = 3;
this.notifyAll();
}
}
public void printC() {
synchronized (this) {
while (turn != 3) {
try {
System.out.println(this.turn);
System.out.println("C");
this.wait();
this.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("C:" + this.turn);
this.turn = 1;
this.notifyAll();
}
}
}
}
下面是在网上看到的另外一个人的代码,觉得虽然针对这个问题,此人写的不是很好,但是思路还是有一定的价值。http://blog.youkuaiyun.com/zyplus/article/details/6672775
public class MyThreadPrinter2 implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThreadPrinter2(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
try{
Thread.sleep(1);
}
catch (InterruptedException e){
e.printStackTrace();
}
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);
MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);
new Thread(pa).start();
Thread.sleep(10);
new Thread(pb).start();
Thread.sleep(10);
new Thread(pc).start();
Thread.sleep(10);
}
}
通过上面的对比可以总结几点:
1 把业务逻辑写到统一的一个类里面进行管理,非常方便,尤其是对互斥的管理,然后线程只需要执行简单的一些执行命令就好了。
2 关于锁的状态,下面的程序中,相比而言缺少了对锁的状态的检查,拿到锁然后就不放手,很容易造成问题,如果对锁的状态进行检查会更好。
3 下面的代码中值得借鉴的是使用了2个锁,最终可以制造一个锁的环路。假设,100个线程一次执行输出1-100的情况下,构造一个锁的环路并且检查锁的状态,会更有效率,因为notifyAll毕竟会随机选择一个等待的线程,如果100个线程同时等待一把锁,而这100个线程又有先后顺序,就会比较低效,因为不知道什时候,锁才能传递过来。
4 研究下java有没有线程通信的机制,如果有的话,也比较适合3中的场景。