实现的java通4个线程顺序打印ABCD四个字母,第一个线程打印A,第二个线程打印B,第三个线程打印C,第四个线程打印D,每个线程打印10次
我说一下我的思路,因为都是打印,所以定义一个用以打印的方法,因为需要线程同步,控制什么时候哪些线程能执行那些线程休眠,所以用synchronized同步块。
下面一些关于同步的知识:
- 每一个对象都有一个互斥的锁标记和一个锁池
- 关键字:synchronized 线程在同步代码中必须采用串行访问
- synchronized修饰的代码块:对括号内的对象object加锁,只有拿到对象锁标记的线程才能进入改代码块。
- 同步依赖对象锁,锁相同,同步语句串行,锁对象不同,同步语句并行
- 调用wait():交出锁和CPU占用,进入线程调用wait对象的等待待池(wait pool)
- 调用notify:将从对象的等待池中移走一个线程并放入锁池中,直接可以获得对象锁标记
首相创建4个对象a、b、c、d
A线程需要获得a和b的锁标记才能执行打印:
synchronized(a){
synchronized(b){
//打印
}
}
B线程需要获得b和c的锁标记才能执行打印:
synchronized(b){
synchronized(c){
//打印
}
}
C线程需要获得c和d的锁标记才能执行打印:
synchronized(c){
synchronized(d){
//打印
}
}
D线程需要获得d和a的锁标记才能执行打印:
synchronized(d){
synchronized(a){
//打印
}
}
刚开始a、b、c、d的等待池中都没有ABCD四个线程,所以ABCD都有机会执行打印方法里打同步代码
A线程执行打印完毕调用b.notify()从b的等待池的中移走一个线程,a.wait()进入a的等待池(a对象等待池:A线程)
B线程执行打印完毕调用c.notify()从b的等待池的中移走一个线程,b.wait()进入a的等待池(b对象等待池:B线程)
C线程执行打印完毕调用d.notify()从b的等待池的中移走一个线程,c.wait()进入a的等待池(c对象等待池:C线程)
D线程执行打印完毕调用a.notify()从b的等待池的中移走一个线程,d.wait()进入a的等待池(d对象等待池:D线程,a对象等待池:没有A线程)
D线程执行完后a和b线程池里都没有A线程,而BCD线程都不能同时获取它们执行打印所需要的两个对象锁标记,所以此时只有A线程能执行打印,
A线程第二次打印往后把b对象等待池的一个线程移走,因为b的等待池只有B线程,所以B线程被移走放入锁池,此时只有B线程能执行打印,以此类推,B打印后只能执行C,C打印后只能执行D,D打印后只能执行A...
因为刚开始一起启用四个线程后不知道哪个线程会先执行打印,所以需要控制线程启动后的首次执行顺,我的做法是在创建线程的类里加两个静态整型变量newIndex和runIndex,每当创建线程的对象是就把当前线程的Id设为newIndex的值,然后newIndex加1,每个线程首次执行打印后都把runIndex加1,当线程执行到synchronized里先判断当前线程的id是否大于runIndex,如果大于说明这个线程是首次执行且还不应该到它执行打印,所以把它在外层synchronized的对象上休眠等待它上一个线程执行答应后唤醒它。
每次一个线程打印完后就休眠了,为了控制每个线程打印完了最后一次直接结束而不是进入休眠所以在打印后需要判断一下是否当前线程已经完成了所以打印次数。
下面是一种实现的代码:
public class ThreadSortPrintABCD implements Runnable {
private static int newIndex = 0;
private static int runIndex = 0;
private int id;
private boolean isFirstRun;
private String name;
private Object self;
private Object next;
private ThreadSortPrintABCD(String name, Object self, Object next) {
id = newIndex++;
this.name = name;
this.self = self;
this.next = next;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (self) {
if(id > runIndex) {
try {
self.wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
System.out.print(name);
if(!isFirstRun) {
runIndex++;
isFirstRun = true;
}
count--;
synchronized (next) {
next.notify();
}
if(count > 0) {
try {
self.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();
Object d = new Object();
ThreadSortPrintABCD pa = new ThreadSortPrintABCD("A", a, b);
ThreadSortPrintABCD pb = new ThreadSortPrintABCD("B", b, c);
ThreadSortPrintABCD pc = new ThreadSortPrintABCD("C", c, d);
ThreadSortPrintABCD pd = new ThreadSortPrintABCD("D", d, a);
new Thread(pa).start();
new Thread(pb).start();
new Thread(pc).start();
new Thread(pd).start();
}
}