【JAVA-线程流水线并发框架架构】

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();
    }
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值