题目:
有三个线程,每个线程,打印A、B、C 的操作,现要求同时执行三个线程,要求打印的顺序为A、B、C 不乱序,重复10次。
思路:
在这里实际上是要进行线程的顺序操作。一般来说,线程的操作是无序的,随机发生的,若只是单纯的让这些线程发生的话,那么ABC的打印顺序自然就是无序的。那么,现在的问题就在于要约束线程的执行。
在我的想法当中,约束线程的执行,那么只需要将不需要运行的线程暂时挂起,让需要运行的线程继续运行就可以达到这种效果了。
那么,在这里,我就将引入一个信号量(Semaphore),利用信号量去控制线程的进行。
或许有的朋友会问信号量是什么,信号量其实就相当于一个大门(临界区)的门锁,信号量则是限制了进入门(临界区)的人数(线程数)。举个例子,当你的信号量为10的时候,若有11个线程申请进入,那么当进入了10个线程之后,临界区的入口则会被挂起,那么,最后的那个线程只能等待,直到已经进入了门(临界区)内的代码执行完毕,释放了信号量才可以进入。
那么,控制线程的顺序执行的原理也是这样的。
当你要打印字母A的时候,那么打印字母BC的线程自然需要挂起,当字母A打印完毕之后,再释放了字母B的信号量,自然就可以打印字母B了,同样,字母C也可以用同样的方法去打印。以此类推,字母ABC就可以按顺序全部打印出来了。
实现
之后则是这个思路的实现方式。
首先,要有三个信号量分别去约束ABC的打印的线程
//信号量只有1则代表只有1个线程可以访问临界区
Semaphore semaphoreA = new Semaphore(1);
Semaphore semaphoreB = new Semaphore(1);
Semaphore semaphoreC = new Semaphore(1);
semaphoreB.acquire();
semaphoreC.acquire();
当然,因为必须要打印字母A为先,所以,一开始就要挂起字母BC的线程
然后则是线程的编写
public class PrintThread extends Thread {
private String word;
private Semaphore thisLock, nextLock;
public PrintThread(String word,Semaphore thisRun,Semaphore nextRun){
this.word = word;
thisLock = thisRun;
nextLock = nextRun;
}
@Override
public void run() {
try {
for(int i = 0;i <10;i++) {
thisLock.acquire();
System.out.print(word);
nextLock.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
当要打印当前字母的时候,首先先将这段代码进入了临界区,这意味着这次打印之后这段代码将会被挂起,直到信号量被释放为止(因为信号量的数量设置为1),然后,在打印之后,释放下一个将要执行的代码的信号量,这意味着打印下一个字母的代码将会被执行,以此类推,就可以一直按顺序执行代码了。
public class Main {
public static void main(String[] args) throws InterruptedException {
// write your code here
//信号量只有1则代表只有1个线程可以访问临界区
Semaphore semaphoreA = new Semaphore(1);
Semaphore semaphoreB = new Semaphore(1);
Semaphore semaphoreC = new Semaphore(1);
semaphoreB.acquire();
semaphoreC.acquire();
PrintThread threadA = new PrintThread("A", semaphoreA, semaphoreB); //锁住当前线程,打开下一个线程的锁
PrintThread threadB = new PrintThread("B", semaphoreB, semaphoreC);
PrintThread threadC = new PrintThread("C", semaphoreC, semaphoreA);
threadA.start();
threadB.start();
threadC.start();
}
}