0.为什么用流水线并发框架架构来实现生产?
提高并发能力:流水线并发框架可以将生产过程分为多个阶段,并将每个阶段分配给不同的工作线程来执行。
提高生产效率:减少任务之间的等待时间,提高生产效率。
可扩展性和解耦性强:不同的阶段可以独立地进行扩展和修改,而不会影响其他阶段。
提高资源利用率:可以通过线程池来管理和重用线程,避免了线程的频繁创建和销毁,提高了线程的利用率。同时通过任务队列的方式,可以平衡不同阶段之间的负载,提高资源的利用效率。。
1.流水线处理模式
如生产一辆汽车,涉及到四个环节,需要依次先后进行,每个环节耗时
1T。
一般生产
5
辆车需要多久?
20T
而
A C1 C2...
B C1 C2...
C C1 C2...
D C1 C2...
E C1 C2 C3 C4
T ----1-----2-------3-----4------5------6-------7------8
流水线生产
5
辆车需要
8T.
import java.util.ArrayList;
/**
* 任务一:执行任务ABC,分为定量任务与不定量任务
* 定量任务:A B C三个任务,对num进行操作,当num==40000时此任务完成,加入list中
* 匿名内部类监听,每一秒钟完成的任务是多少,输出list中已完成的任务量
* 存在问题:进入死循环 显示完成的任务量为0。此问题为可见性问题。
*/
public class Task {
int num = 0;
public void taskA(){
num += 10;
}
public void taskB(){
num *= 20;
}
public void taskC(){
num *= num;
}
}
class TA extends Thread{
ArrayList <Task> list;
//构造方法
public TA(ArrayList <Task> list){
this.list = list;
}
@Override
public void run() {
//每一个run方法,都对list进行遍历
for (int i = 0; i < list.size(); i++) {
Task task = list.get(i);
task.taskA();
}
}
}
class TB extends Thread{
ArrayList <Task> list;
public TB(ArrayList <Task> list){
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < list.size(); i++) {
Task task = list.get(i);
task.taskB();
}
}
}
class TC extends Thread{
ArrayList <Task> list;
public TC(ArrayList <Task> list){
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < list.size(); i++) {
Task task = list.get(i);
task.taskC();
}
}
}
class Main{
public static void main(String[] args) {
//1.定量任务 可以用链表实现
ArrayList <Task> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
list.add(new Task());
}
//TA TB TC
TA ta = new TA(list);
TB tb = new TB(list);
TC tc = new TC(list);
ta.start();
tb.start();
tc.start();
/**
* 监听状态线程
* 匿名内部类形式
* 每一秒钟监听任务量完成了多少
*/
new Thread(){
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
int size = 0;
for (int i = 0; i < list.size(); i++) {
if(list.get(i).num == 40000){
size++;
}
}
System.out.println("已完成的任务量为:"+size);
}
}
}.start();
try {
ta.join();
}catch (InterruptedException e){
throw new RuntimeException(e);
}
//2.不定量任务(实时产生)
new Thread(){
@Override
public void run() {
while (true){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
list.add(new Task());
}
}
}.start();
}
}
2.可见性问题
线程中使用的变量是从堆内存中复制的副本。当
A
线程操作完这个变量之后,修改堆内存中变量的值后,另一个B
线程并不知道
A
线程已经修改了堆内存中变量的值 ,这个时候B
线程还是在使用之前拷贝来的副本,出现错误。
/**
* 可见性问题
*/
public class Visible {
volatile static boolean flag;// 每次使用变量时 都会重新拷贝一份副本过来
public static void main(String[] args) {
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("T1 - start");
flag = true;
System.out.println("T1 - end");
}
};
new Thread() {
@Override
public void run() {
System.out.println("T2-start");
while (!flag) {
/**
* 问题:没有输出语句时,一直死循环
* 原因:使用的本地副本没有及时更新。
* 可见性:一个线程对共享变量的修改要能够及时反映到其他线程
* 此处有print输出语句能够解决问题。因为print源码中调用的write方法有synchronized,是一个原子性的方法,每次调用时会去
* 内存中查看是否加锁,如果有锁就去堆内存中更新数据,把本地变量表更新一遍,以此解决输出不了的问题。
* 解决方法二:变量 volatile 每次使用变量时 都会重新拷贝一份副本过来
*/
// System.out.print("");
}
System.out.println("T2-end");
}
}.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
t1.start();
}
}
3.如何有序的处理这些任务?
第一种方式:用时间来换
1)加上约束条件;
2)重复检验。
package day06_流水线处理模式;
/**
* 任务二:设定三个变量,保证能够通信
* taskABC加上约束条件:A任务没执行过才执行;B任务要A任务执行过才执行;C任务要B任务执行过才执行
* run方法中加上while,多次遍历,直到任务完成为止
*/
import java.util.ArrayList;
public class Task2 {
int num;
boolean flagA = false;
boolean flagB = false;
boolean flagC = false;
public void taskA() {
if (!flagA) {
sleep(40);
num += 10;
flagA = true;
}
}
public void taskB() {
if (!flagB && flagA) {
sleep(30);
num *= 20;
flagB = true;
}
}
public void taskC() {
if (flagB && !flagC) {
sleep(30);
num *= num;
flagC = true;
}
}
public boolean isEnd() {
return flagC;
}
public void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TA2 extends Thread {
ArrayList<Task2> list;
public TA2(ArrayList<Task2> list) {
this.list = list;
}
@Override
public void run() {
int count = 0;
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("TA - run" + count++);
int size = 0;
for (int i = 0; i < list.size(); i++) {
Task2 task = list.get(i);
task.taskA();
if (task.flagA) {
size++;
}
}
System.out.println("TA - 完成了" + size);
if (size == list.size()) {
break;
}
}
}
}
class TB2 extends Thread {
ArrayList<Task2> list;
public TB2(ArrayList<Task2> list) {
this.list = list;
}
@Override
public void run() {
int count = 0;
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("TB - run" + count++);
int size = 0;
for (int i = 0; i < list.size(); i++) {
Task2 task = list.get(i);
task.taskB();
if (task.flagB) {
size++;
}
}
System.out.println("TB - 完成了" + size);
if (size == list.size()) {
break;
}
}
}
}
class TC2 extends Thread {
ArrayList<Task2> list;
public TC2(ArrayList<Task2> list) {
this.list = list;
}
@Override
public void run() {
int count = 0;
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("TC - run" + count++);
int size = 0;
for (int i = 0; i < list.size(); i++) {
Task2 task = list.get(i);
task.taskC();
if (task.flagC) {
size++;
}
}
System.out.println("TC - 完成了" + size);
if (size == list.size()) {
break;
}
}
}
}
class Main2 {
public static void main(String[] args) {
// 1: 定量任务
ArrayList<Task2> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(new Task2());
}
TA2 ta = new TA2(list);
TB2 tb = new TB2(list);
TC2 tc = new TC2(list);
ta.start();
tb.start();
tc.start();
// 监听状态线程
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
int size = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).num == 40000) {
size++;
}
}
System.out.println(list.size());
System.out.println("已完成:" + size + "任务");
}
}
}.start();
try {
ta.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
tb.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
tc.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// for (int i = 0; i < list.size(); i++) {
// System.out.println(list.get(i).num);
// }
}
}
第二种方式:阻塞任务
将任务数组看成一个队列,A第一个任务没有执行,第二个线程不会执行任何任务。
import java.util.ArrayList;
/**
* 方法二: 阻塞任务 (堵车)
* 将任务数组看成一个队列,A第一个任务没有执行,第二线程不会执行任何任务
* 在taskB中,判断A是否执行,若执行则继续,若没有执行B会一直死循环阻塞;C也是B没执行则阻塞
* 注意:三个变量在不同线程都有用到,所以要加上volatile(可见性问题)
* 500个任务一般每个耗时0.1s,需50s,利用阻塞任务可以看到 耗时:23927 ms 节省一半时间
* 存在问题:如果一个任务出现问题,整个流水线都会崩掉
* 如下图,如果B任务出错,整个任务不会继续跑,其余95个任务也跑不了
*/
// A-B-C : 40000 正确完成任务后的结果
public class Task3 {
int num;
volatile boolean flagA = false;
volatile boolean flagB = false;
volatile boolean flagC = false;
public void taskA() {
if (!flagA) {
sleep(40);
num += 10;
flagA = true;
}
}
public void taskB() {
while (!flagA) {// 阻塞
}
if (!flagB) {
sleep(30);
num *= 20;
flagB = true;
}
}
public void taskC() {
while (!flagB) {// 阻塞
}
if (!flagC) {
sleep(30);
num *= num;
flagC = true;
}
}
public boolean isEnd() {
return flagC;
}
public void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TA extends Thread {
ArrayList<Task3> list;
public TA(ArrayList<Task3> list) {
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < list.size(); i++) {
Task3 task = list.get(i);
task.taskA();
}
}
}
class TB extends Thread {
ArrayList<Task3> list;
public TB(ArrayList<Task3> list) {
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < list.size(); i++) {
Task3 task = list.get(i);
/**
* 此处模拟B任务崩溃
* 会一直卡在5这个任务上
*/
// if (i == 5) {
// continue;
// }
task.taskB();
}
}
}
class TC extends Thread {
ArrayList<Task3> list;
public TC(ArrayList<Task3> list) {
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < list.size(); i++) {
Task3 task = list.get(i);
task.taskC();
}
}
}
class Main {
public static void main(String[] args) {
// 1: 定量任务
ArrayList<Task3> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
list.add(new Task3());
}
TA ta = new TA(list);
TB tb = new TB(list);
TC tc = new TC(list);
ta.start();
tb.start();
tc.start();
// 监听状态线程
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
int size = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).num == 40000) {
size++;
}
}
System.out.println(list.size());
System.out.println("已完成:" + size + "任务");
}
}
}.start();
long start = System.currentTimeMillis();
try {
ta.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
tb.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
tc.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
long end = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).num);
}
System.out.println("耗时:" + (end - start) + " ms");
}
}
第三种方法:系统化,模块化
用空间换效率
1.生产任务线程速度快,入口池迅速饱满问题:入口池使用阻塞定量队列,达到负载80%告知生产任务线程停止;
2.队列过长,内存爆满问题;
3.线程过多:使用线程池(加锁,内部用队列);
package day06_流水线处理模式.v5;
import java.util.ArrayList;// A-B-C : 40000 正确完成任务后的结果
import java.util.LinkedList;
import java.util.concurrent.ArrayBlockingQueue;
/**
* put方法在向队列添加元素时,如果队列已满,则会阻塞等待队列空间可用。换句话说,当队列已满时,put方法会使当前线程阻塞,直到队列有空间可以放入元素。
* 这种行为符合阻塞队列的特性,即当队列已满时,生产者线程会等待直到队列有空间。
*
* offer方法向队列添加元素时,如果队列已满,则会立即返回false,不会阻塞等待。这就意味着,
* 当队列已满时,offer方法会返回一个标识来表示添加元素是否成功,而不会等待队列有空间
*/
/**
* 版本一:不用阻塞队列,实现系统化
*/
//public class Task {
// int num;
// public void taskA() {
// num += 10;
// }
// public void taskB() {
// num *= 20;
// }
// public void taskC() {
// num *= num;
// }
//}
//class TA extends Thread {
// LinkedList<Task> taskB;
// LinkedList<Task> taskA;
// public TA(LinkedList<Task> taskA, LinkedList<Task> taskB) {
// this.taskB = taskB;
// this.taskA = taskA;
// }
// @Override
// public void run() {
// while (true) {
// Task task = taskA.poll();// 出列
// if (task != null) {
// task.taskA();// 执行A任务
// taskB.offer(task);// 入队B
// }
// }
// }
//}
//class TB extends Thread {
// LinkedList<Task> taskB;
// LinkedList<Task> taskC;
// public TB(LinkedList<Task> taskB, LinkedList<Task> taskC) {
// this.taskB = taskB;
// this.taskC = taskC;
// }
// @Override
// public void run() {
// while (true) {
// Task task = taskB.poll();// 出列
// if (task != null) {
// task.taskB();// 执行A任务
// taskC.offer(task);// 入队B
// }
// }
// }
//}
//class TC extends Thread {
// ArrayList<Task> tasks;
// LinkedList<Task> taskC;
// public TC(LinkedList<Task> taskC, ArrayList<Task> tasks) {
// this.tasks = tasks;
// this.taskC = taskC;
// }
// @Override
// public void run() {
// while (true) {
// Task task = taskC.poll();// 出列
// if (task != null) {
// task.taskC();// 执行A任务
// tasks.add(task);// 入队B
// }
// }
// }
//}
//class Main {
// public static void main(String[] args) {
1: 定量任务
// LinkedList<Task> taskA = new LinkedList<>();// A的原料库
// LinkedList<Task> taskB = new LinkedList<>();// B的原料库
// LinkedList<Task> taskC = new LinkedList<>();// C的原料库
// ArrayList<Task> tasks = new ArrayList<>();// 成品库
// ArrayBlockingQueue<Task> tasks1 = new ArrayBlockingQueue<>(50);
// for (int i = 0; i < 500; i++) {
// taskA.offer(new Task());// 入队
// }
// TA ta = new TA(taskA, taskB);
// TB tb = new TB(taskB, taskC);
// TC tc = new TC(taskC, tasks);
// ta.start();
// tb.start();
// tc.start();
监听状态线程
// new Thread() {
// @Override
// public void run() {
// while (true) {
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// int size = 0;
// for (int i = 0; i < tasks.size(); i++) {
// System.out.println(tasks.get(i).num);
// if (tasks.get(i).num == 40000) {
// size++;
// }
// }
// System.out.println(tasks.size());
// System.out.println("已完成:" + size + "任务");
// }
// }
// }.start();
// }
//}
/**
* 版本二:用阻塞队列,实现系统化
*/
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
public class Task {
int num;
public void taskA() {
num += 10;
}
public void taskB() {
num *= 20;
}
public void taskC() {
num *= num;
}
}
class TA extends Thread {
ArrayBlockingQueue<Task> taskA;
ArrayBlockingQueue<Task> taskB;
public TA(ArrayBlockingQueue<Task> taskA, ArrayBlockingQueue<Task> taskB) {
this.taskA = taskA;
this.taskB = taskB;
}
@Override
public void run() {
while (true) {
try {
Task task = taskA.take();// 出队
task.taskA();// 执行A任务
taskB.put(task);// 入队B
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class TB extends Thread {
ArrayBlockingQueue<Task> taskB;
ArrayBlockingQueue<Task> taskC;
public TB(ArrayBlockingQueue<Task> taskB, ArrayBlockingQueue<Task> taskC) {
this.taskB = taskB;
this.taskC = taskC;
}
@Override
public void run() {
while (true) {
try {
Task task = taskB.take();// 出队
task.taskB();// 执行B任务
taskC.put(task);// 入队C
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class TC extends Thread {
ArrayBlockingQueue<Task> taskC;
ArrayList<Task> tasks;
public TC(ArrayBlockingQueue<Task> taskC, ArrayList<Task> tasks) {
this.taskC = taskC;
this.tasks = tasks;
}
@Override
public void run() {
while (true) {
try {
Task task = taskC.take();// 出队
task.taskC();// 执行C任务
tasks.add(task);// 加入成品库
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class Main {
public static void main(String[] args) {
/**
* A的原料库有待确认
*/
ArrayBlockingQueue<Task> taskA = new ArrayBlockingQueue<>(500);// A的原料库
ArrayBlockingQueue<Task> taskB = new ArrayBlockingQueue<>(50);// B的原料库
ArrayBlockingQueue<Task> taskC = new ArrayBlockingQueue<>(50);// C的原料库
ArrayList<Task> tasks = new ArrayList<>();// 成品库
/**
* 此处i有很大关系。如果 i = 500,会在capacity = 50后阻塞
* 需要处理阻塞,等待队列有空闲时才能继续入队列
* 所以此处将所有的任务都入队列A是不正常的
* 或者对A的原料库重新设置
*/
for (int i = 0; i < 500; i++) {
try {
taskA.put(new Task());// 入队
System.out.println("已完成任务入队列A");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
TA ta = new TA(taskA, taskB);
TB tb = new TB(taskB, taskC);
TC tc = new TC(taskC, tasks);
System.out.println("已完成线程的创建");
ta.start();
tb.start();
tc.start();
System.out.println("已完成线程的启动");
// 监听状态线程
new Thread(() -> {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
int size = 0;
// for (Task t : tasks) {
// System.out.println(t.num);
// if (t.num == 40000) {
// size++;
// }
// }
for (int i = 0; i < tasks.size(); i++) {
System.out.println(tasks.get(i).num);
if (tasks.get(i).num == 40000) {
size++;
}
}
System.out.println(tasks.size());
System.out.println("已完成:" + size + "任务");
}
}).start();
}
}