利用多线程实现流水线的目的
v0版流水线原理
具体代码演示
- 利用流水线的目的
把一个大任务拆分成多个小任务
在完成第一个分任务之后便可以开始第二个大任务的第一个分任务,大大节约了时间
- v0版流水线的原理
v0版流水线原理示意图
难点1:怎么保证流水线按照顺序执行?
由人工流水线试想如何让计算机达到像人工那样工作?
假设三个人甲乙丙一起完成造小车这项工作,甲完成了任务一之后会告诉乙“我完成了”,或者是乙通过观察,发现小车有了外壳,但没有发动机,意识到该自己做了,然后拿过半成品,进行分任务2.
这里的甲的话,或是乙的观察都是信号,让乙知道“It's my turn",这才有了turn(顺序)
同样的,我们需要给计算机信号,在任务一执行后有信号,在执行任务二前可以获得这个信号,这样就可以实现由甲到乙,由任务一到任务二的顺序
boolean flag1;
//java中布尔值默认为false
boolean flag2;
public void task1(){
if(!flag1){
num=10;
System.out.println("执行了任务1");
flag1=true;
//既是给任务二的信号,也可以保证不会被重复执行任务一
}}
public void task2(){
if(!flag2&&flag1){
num*=num;
System.out.println("执行了任务2");
flag2=true;
}}
难点1.1:计算机是个大傻子,即线程启动的随机性无法改变,怎么办呢?
上述操作的确可以保证整个大任务由123这样的顺序进行,但是如果先取任务的是分任务2,取的少,分任务1后取,取的多,那么之后的会有生产出的小车,但是前边一部分便无法产生出小车,极端情况下,分任务2先取,且每次多于分任务1,那么便永远无法生产小车因为需要保证是12,而不是21,这个顺序
以上描述的问题如下图所示
怎么解决嘞?
我们要是让分任务二这个线程再走一遍,是不是至少来说大任务一二三是可以进行第二分任务这一步了,因为大任务一二三的分任务1都已经完成。所以我们就可以通过让分任务1以外的其他分任务每隔一段时间再遍历一下任务组,说白了就是看看上一次遍历时候分任务1还没完成的任务,过了一段时间之后完成没,完成了就可以拿来进行分任务2了
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//每隔一段时间重新遍历
for (int i = 0; i < al.size(); i++) {
Task task = al.get(i);
System.out.println("thread1取出第" + i + "个任务");
task.task1();
- 具体代码演示
产生一个任务池子
public class ProduceTaskThread implements Runnable{
//创建一个ArrayList用于存放生成的任务
ArrayList<Task> al;
public ProduceTaskThread(ArrayList<Task> al) {
this.al = al;
}
@Override
public void run() {
for(int i=0;i<500;i++){
Task task=new Task();
al.add(task);
}
System.out.println("已经自动生成"+al.size()+"个任务");
}
}
创建一个任务类
public class Task {
int num;
boolean flag1;
//java中布尔值默认为false
boolean flag2;
boolean flag3;
//设置标记
public void task1(){
if(!flag1){
num=10;
System.out.println("执行了任务1");
flag1=true;
}}
public void task2(){
if(!flag2&&flag1){
num*=num;
System.out.println("执行了任务2");
flag2=true;
}}
public void task3(){
if(!flag3&&flag2){
num+=2;
System.out.println("执行了任务3");
flag3=true;}
}
分任务线程
以一个分线程为例
class Task_Thread01 implements Runnable{
ArrayList<Task> al;
public Task_Thread01(ArrayList<Task> al) {
this.al = al;
}
@Override
public void run() {
while(true) {
//task1其实不需要
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
int count=0;
for (int i = 0; i < al.size(); i++) {
Task task = al.get(i);
// System.out.println("thread1取出第" + i + "个任务");
task.task1();
}}
}
查看代码运行结果
线程全部跑完才能查看到最后的结果
怎么结束任务嘞?
以一个分任务为例
if (task.flag1) {
count++;
}
}
if(count==500){
break;
}
Thread的join方法:
当前线程结束后才会执行后边的代码
分任务3结束后整个全部任务就真的结束了,所以用t3.join,之后,查看结果
try {
t3.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//查看结果
//像数组、动态数组中所有数据的查看都是用到for遍历的
//不是直接SOP
for(int i=0;i<al.size();i++){
Task task=al.get(i);
System.out.println(task.num);
}