Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中生产者-消费者多线程FIFO_Java_Multithreading_Parallel Processing_Semaphore_Producer Consumer - Fatal编程技术网

Java中生产者-消费者多线程FIFO

Java中生产者-消费者多线程FIFO,java,multithreading,parallel-processing,semaphore,producer-consumer,Java,Multithreading,Parallel Processing,Semaphore,Producer Consumer,社区,我试图用10个线程来解决生产者/消费者的问题,但我在实现它时遇到了困难 问题是这样的: 程序本身在插入包含(id,timeout)的消息时应该有一个循环,以id(1,2,3,4…)的升序进行,并且应该简单地打印出来的消息的id,与它输入的顺序相同,就像一个队列 例如,在上面的照片中,3条消息Message(1200)、Message(2100)和Message(3,20)是制作人将生成的前3条消息。 虽然分配了消息(3,20)的线程应该首先打印(因为它有最低的超时时间(20)),但我希望

社区,我试图用10个线程来解决生产者/消费者的问题,但我在实现它时遇到了困难

问题是这样的:

程序本身在插入包含(id,timeout)的消息时应该有一个循环,以id(1,2,3,4…)的升序进行,并且应该简单地打印出来的消息的id,与它输入的顺序相同,就像一个队列

例如,在上面的照片中,3条消息Message(1200)、Message(2100)和Message(3,20)是制作人将生成的前3条消息。 虽然分配了消息(3,20)的线程应该首先打印(因为它有最低的超时时间(20)),但我希望它等待第一条超时时间为200ms的消息打印,然后再次等待打印时间为1000ms的消息2,然后打印它自己。因此,所有这些都是按递增顺序排列的(可能使用id作为订购号?)

到目前为止,我已经实现了这一点:

public class Main {

    private static BlockingQueue<Message> queue = new ArrayBlockingQueue<>(5);

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(() -> {
            try {
                producer();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                consumer();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();
    }

    public static void producer() throws InterruptedException {

        while (true) {
            queue.put(new Message());
        }
    }

    public static void consumer() throws InterruptedException {

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 1000; i++) {
            executorService.submit(queue.take());
        }
        executorService.shutdown();
    }
}
到目前为止,除了线程应该等待具有优先级id的线程的部分,它做的一切都很好。。。以下是输出的第一部分:

All tasks submitted
pool-1-thread-9[RECEIVED] Message = Message{id=13, timeout=1361}
pool-1-thread-10[RECEIVED] Message = Message{id=14, timeout=92}
pool-1-thread-3[RECEIVED] Message = Message{id=7, timeout=3155}
pool-1-thread-5[RECEIVED] Message = Message{id=9, timeout=562}
pool-1-thread-2[RECEIVED] Message = Message{id=6, timeout=4249}
pool-1-thread-1[RECEIVED] Message = Message{id=0, timeout=1909}
pool-1-thread-7[RECEIVED] Message = Message{id=11, timeout=2468}
pool-1-thread-4[RECEIVED] Message = Message{id=8, timeout=593}
pool-1-thread-8[RECEIVED] Message = Message{id=12, timeout=3701}
pool-1-thread-6[RECEIVED] Message = Message{id=10, timeout=806}
pool-1-thread-10[DONE] Message = Message{id=14, timeout=92}

pool-1-thread-10[RECEIVED] Message = Message{id=15, timeout=846}
pool-1-thread-5[DONE] Message = Message{id=9, timeout=562}

pool-1-thread-5[RECEIVED] Message = Message{id=16, timeout=81}
pool-1-thread-4[DONE] Message = Message{id=8, timeout=593}

pool-1-thread-4[RECEIVED] Message = Message{id=17, timeout=4481}
pool-1-thread-5[DONE] Message = Message{id=16, timeout=81}

pool-1-thread-5[RECEIVED] Message = Message{id=18, timeout=2434}
pool-1-thread-6[DONE] Message = Message{id=10, timeout=806}

pool-1-thread-6[RECEIVED] Message = Message{id=19, timeout=10}
pool-1-thread-6[DONE] Message = Message{id=19, timeout=10}

pool-1-thread-6[RECEIVED] Message = Message{id=20, timeout=3776}
pool-1-thread-10[DONE] Message = Message{id=15, timeout=846}

pool-1-thread-10[RECEIVED] Message = Message{id=21, timeout=2988}
pool-1-thread-9[DONE] Message = Message{id=13, timeout=1361}

pool-1-thread-9[RECEIVED] Message = Message{id=22, timeout=462}
pool-1-thread-9[DONE] Message = Message{id=22, timeout=462}

pool-1-thread-9[RECEIVED] Message = Message{id=23, timeout=3074}
pool-1-thread-1[DONE] Message = Message{id=0, timeout=1909}

pool-1-thread-1[RECEIVED] Message = Message{id=24, timeout=725}
pool-1-thread-7[DONE] Message = Message{id=11, timeout=2468}
我的一个朋友告诉我应该使用信号量(从来没有使用过信号量),但我真的不知道如何实现信号量,让它们做我想做的事情


感谢任何解决这个问题的线索

据我所知,你需要两件事:

  • 同时启动所有生产者的工作线程,让它们并行运行,但是
  • 等待线程以FIFO顺序完成(根据其创建id)
  • 因此,您可以一个接一个地启动线程,以便让它们并行运行,但也可以按id升序维护FIFO队列,只需按照添加到队列中的顺序加入每个线程即可

    下面是一个演示代码,说明如何执行此操作:

    import java.util.LinkedList;
    import java.util.Objects;
    import java.util.Random;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;
    import java.util.function.Consumer;
    
    public class Main {
        
        private static class Message implements Runnable {
            private final TimeUnit sleepUnit;
            private final long sleepAmount;
            private final int id;
            
            public Message(final int id,
                           final TimeUnit sleepUnit,
                           final long sleepAmount) {
                this.sleepUnit = Objects.requireNonNull(sleepUnit);
                this.sleepAmount = sleepAmount;
                this.id = id;
            }
            
            @Override
            public void run() {
                try {
                    System.out.println(toString() + " started and waiting...");
                    sleepUnit.sleep(sleepAmount);
                }
                catch (final InterruptedException ix) {
                    System.out.println(toString() + " interrupted: " + ix);
                }
            }
            
            @Override
            public String toString() {
                return "Message{" + id + ", " + sleepUnit + "(" + sleepAmount + ")}";
            }
        }
        
        private static class Producer {
            
            private final int parallelism;
            private final Consumer<? super Producer> consumer;
            
            public Producer(final int parallelism,
                            final Consumer<? super Producer> consumer) {
                this.parallelism = parallelism;
                this.consumer = Objects.requireNonNull(consumer);
            }
            
            public void produceWithExecutor() {
                System.out.println("Producing with Executor...");
                final Random rand = new Random();
                final ExecutorService service = Executors.newFixedThreadPool(parallelism);
                final LinkedList<Future> q = new LinkedList<>();
                for (int i = 0; i < parallelism; ++i) {
                    final Message msg = new Message(i, TimeUnit.MILLISECONDS, 500 + rand.nextInt(3000));
                    q.addLast(service.submit(msg, msg));
                }
                service.shutdown();
                while (!q.isEmpty())
                    try {
                        System.out.println(q.removeFirst().get().toString() + " joined."); //Will wait for completion of each submitted task (in FIFO sequence).
                    }
                    catch (final InterruptedException ix) {
                        System.out.println("Interrupted: " + ix);
                    }
                    catch (final ExecutionException xx) {
                        System.out.println("Execution failed: " + xx);
                    }
                consumer.accept(this);
            }
            
            public void produceWithPlainThreads() throws InterruptedException {
                System.out.println("Producing with Threads...");
                final Random rand = new Random();
                final LinkedList<Thread> q = new LinkedList<>();
                for (int i = 0; i < parallelism; ++i) {
                    final Message msg = new Message(i, TimeUnit.MILLISECONDS, 500 + rand.nextInt(3000));
                    final Thread t = new Thread(msg, msg.toString());
                    t.start();
                    q.add(t);
                }
                while (!q.isEmpty()) {
                    final Thread t = q.removeFirst();
                    t.join(); //Will wait for completion of each submitted task (in FIFO sequence).
                    System.out.println(t.getName() + " joined.");
                }
                consumer.accept(this);
            }
        }
        
        public static void main(final String[] args) throws InterruptedException {
            final Consumer<Producer> consumer = producer -> System.out.println("Consuming.");
            final int parallelism = 10;
            new Producer(parallelism, consumer).produceWithExecutor();
            new Producer(parallelism, consumer).produceWithPlainThreads();
        }
    }
    
    import java.util.LinkedList;
    导入java.util.Objects;
    导入java.util.Random;
    导入java.util.concurrent.ExecutionException;
    导入java.util.concurrent.ExecutorService;
    导入java.util.concurrent.Executors;
    导入java.util.concurrent.Future;
    导入java.util.concurrent.TimeUnit;
    导入java.util.function.Consumer;
    公共班机{
    私有静态类消息实现可运行{
    私人终场计时装置;
    私人最终长期睡眠量;
    私有最终int id;
    公共消息(最终int id,
    最终计时单位睡眠单位,
    最终长期睡眠量){
    this.sleepUnit=Objects.requirennoull(sleepUnit);
    this.sleepAmount=sleepAmount;
    this.id=id;
    }
    @凌驾
    公开募捐{
    试一试{
    System.out.println(toString()+“已启动并等待…”);
    睡眠单位。睡眠(睡眠量);
    }
    捕获(最终中断异常ix){
    System.out.println(toString()+“中断:”+ix);
    }
    }
    @凌驾
    公共字符串toString(){
    返回“Message{“+id+”,“+sleepUnit+”(“+sleepAmount+”)}”;
    }
    }
    私有静态类生产者{
    私有最终整数并行;
    
    private final Consumer在线程内使用ExecutorService有什么意义?此外,您的生产者不断生成具有随机睡眠时间的消息。因此,如果您尝试仅生成10条消息并消费10条消息,您将看到线程按睡眠时间顺序运行,但当
    queue.take()时
    一个线程不知道睡眠时间,因此此日志是正常的。我在该消费者线程内使用ExecutorService,因为我希望有10个线程处理消息。此外,我没有试图生成10条消息和消费10条消息,我试图生成N条消息,这与数字无关,甚至可能是一个无限数消息的r…基本上我不能做的全部事情就是告诉我的线程彼此等待,以便它们按照输入的相同顺序打印消息。(这是升序:1,2,3,4,5,6…)是的,这就是异步编程的要点。非常感谢!这帮了大忙!
    import java.util.LinkedList;
    import java.util.Objects;
    import java.util.Random;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;
    import java.util.function.Consumer;
    
    public class Main {
        
        private static class Message implements Runnable {
            private final TimeUnit sleepUnit;
            private final long sleepAmount;
            private final int id;
            
            public Message(final int id,
                           final TimeUnit sleepUnit,
                           final long sleepAmount) {
                this.sleepUnit = Objects.requireNonNull(sleepUnit);
                this.sleepAmount = sleepAmount;
                this.id = id;
            }
            
            @Override
            public void run() {
                try {
                    System.out.println(toString() + " started and waiting...");
                    sleepUnit.sleep(sleepAmount);
                }
                catch (final InterruptedException ix) {
                    System.out.println(toString() + " interrupted: " + ix);
                }
            }
            
            @Override
            public String toString() {
                return "Message{" + id + ", " + sleepUnit + "(" + sleepAmount + ")}";
            }
        }
        
        private static class Producer {
            
            private final int parallelism;
            private final Consumer<? super Producer> consumer;
            
            public Producer(final int parallelism,
                            final Consumer<? super Producer> consumer) {
                this.parallelism = parallelism;
                this.consumer = Objects.requireNonNull(consumer);
            }
            
            public void produceWithExecutor() {
                System.out.println("Producing with Executor...");
                final Random rand = new Random();
                final ExecutorService service = Executors.newFixedThreadPool(parallelism);
                final LinkedList<Future> q = new LinkedList<>();
                for (int i = 0; i < parallelism; ++i) {
                    final Message msg = new Message(i, TimeUnit.MILLISECONDS, 500 + rand.nextInt(3000));
                    q.addLast(service.submit(msg, msg));
                }
                service.shutdown();
                while (!q.isEmpty())
                    try {
                        System.out.println(q.removeFirst().get().toString() + " joined."); //Will wait for completion of each submitted task (in FIFO sequence).
                    }
                    catch (final InterruptedException ix) {
                        System.out.println("Interrupted: " + ix);
                    }
                    catch (final ExecutionException xx) {
                        System.out.println("Execution failed: " + xx);
                    }
                consumer.accept(this);
            }
            
            public void produceWithPlainThreads() throws InterruptedException {
                System.out.println("Producing with Threads...");
                final Random rand = new Random();
                final LinkedList<Thread> q = new LinkedList<>();
                for (int i = 0; i < parallelism; ++i) {
                    final Message msg = new Message(i, TimeUnit.MILLISECONDS, 500 + rand.nextInt(3000));
                    final Thread t = new Thread(msg, msg.toString());
                    t.start();
                    q.add(t);
                }
                while (!q.isEmpty()) {
                    final Thread t = q.removeFirst();
                    t.join(); //Will wait for completion of each submitted task (in FIFO sequence).
                    System.out.println(t.getName() + " joined.");
                }
                consumer.accept(this);
            }
        }
        
        public static void main(final String[] args) throws InterruptedException {
            final Consumer<Producer> consumer = producer -> System.out.println("Consuming.");
            final int parallelism = 10;
            new Producer(parallelism, consumer).produceWithExecutor();
            new Producer(parallelism, consumer).produceWithPlainThreads();
        }
    }