用JAVA自己实现一套背压机制

单线程版本:

一个生产者,一个消费者


import lombok.SneakyThrows;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class BackpressureExample {
    public static void main(String[] args) throws InterruptedException {
        BackpressureSubscriber subscriber = new BackpressureSubscriber();
        BackpressurePublisher publisher = new BackpressurePublisher(subscriber);
        publisher.start();
        subscriber.start();
        // 为了演示效果,这里让主线程休眠一段时间
        Thread.sleep(50000);
        publisher.stop();
        subscriber.stop();
    }

    @SneakyThrows
    public static void processDataLogic(List<Integer> batch) {
        //模拟任务执行
        int r = new Random().nextInt(3000);
        Thread.sleep(r);
        System.out.println(Thread.currentThread().getName() + ",Received batch: " + batch + ",sleep ms = " + r);
    }

    static class BackpressurePublisher {
        private final BackpressureSubscriber subscriber;
        private volatile boolean running;

        public BackpressurePublisher(BackpressureSubscriber subscriber) {
            this.subscriber = subscriber;
            this.running = true;
        }

        public void start() {
            Thread thread = new Thread(() -> {
                int item = 1;
                while (running) {
                    List<Integer> batch = new ArrayList<>();
                    for (int i = 0; i < 5; i++) {
                        System.out.println(Thread.currentThread().getName() + "-----produce data = " + item);
                        batch.add(item++);
                    }
                    while (!subscriber.accept(batch)) {
                        if (!running) {
                            break;
                        }
                    }
                }
            });
            thread.start();
        }

        public void stop() {
            running = false;
        }
    }

    static class BackpressureSubscriber {
        private volatile boolean running;

        public BackpressureSubscriber() {
            this.running = true;
        }

        public boolean accept(List<Integer> batch) {
            if (running) {
                processDataLogic(batch);
                return true;
            } else {
                return false;
            }
        }

        public void start() {
            // Subscriber 在 JDK 8 中没有异步处理的能力,因此不需要单独开启线程
        }

        public void stop() {
            running = false;
        }
    }
}


多线程版本

一个生产者,多个消费者


import lombok.SneakyThrows;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class BackpressureExample {
    public static void main(String[] args) throws InterruptedException {
        BackpressureSubscriber subscriber = new BackpressureSubscriber();
        BackpressurePublisher publisher = new BackpressurePublisher(subscriber);
        publisher.start();
        subscriber.start();
        // 为了演示效果,这里让主线程休眠一段时间
        Thread.sleep(50000);
        publisher.stop();
        subscriber.stop();
    }

    @SneakyThrows
    public static void processDataLogic(List<Integer> batch) {
        //模拟任务执行
        int r = new Random().nextInt(3000);
        Thread.sleep(r);
        System.out.println(Thread.currentThread().getName() + ",Received batch: " + batch + ",sleep ms = " + r);
    }

    static class BackpressurePublisher {
        private final BackpressureSubscriber subscriber;
        private volatile boolean running;

        public BackpressurePublisher(BackpressureSubscriber subscriber) {
            this.subscriber = subscriber;
            this.running = true;
        }

        public void start() {
            Thread thread = new Thread(() -> {
                int item = 1;
                while (running) {
                    List<Integer> batch = new ArrayList<>();
                    for (int i = 0; i < 5; i++) {
                        System.out.println(Thread.currentThread().getName() + "-----produce data = " + item);
                        batch.add(item++);
                    }
                    while (!subscriber.accept(batch)) {
                        if (!running) {
                            break;
                        }
                    }
                }
            });
            thread.start();
        }

        public void stop() {
            running = false;
        }
    }

    static class BackpressureSubscriber {
        private volatile boolean running;
        private final ExecutorService executor;
        private final int workerSize = 2;
        private final List<Future> futures;

        public BackpressureSubscriber() {
            this.running = true;
            this.executor = Executors.newFixedThreadPool(workerSize);
            futures = new ArrayList<>(workerSize);
        }

        public boolean accept(List<Integer> batch) {
            if (running) {
                Future f = executor.submit(() -> processDataLogic(batch));
                futures.add(f);
                waitForTaskDone(futures);
                return true;
            } else {
                return false;
            }
        }

        public void waitForTaskDone(List<Future> futures) {
            while (futures.size() >= workerSize) {
                for (Future future : futures) {
                    if (future.isDone()) {
                        // 只要有一个worker是空闲就重新获取任务
                        futures.remove(future);
                        return;
                    }
                }
            }
        }

        public void start() {
            // Subscriber 在 JDK 8 中没有异步处理的能力,因此不需要单独开启线程
        }

        public void stop() {
            running = false;
            executor.shutdown();
        }
    }
}


posted @ 2023-06-30 08:37  hwp0710  阅读(64)  评论(0编辑  收藏  举报