简体   繁体   English

多个延迟消费者、并发句柄、BlockingQueue

[英]Multiple Delayed Consumer, Concurrence handle, BlockingQueue

NOTE: I have really tried to simplify this code注意:我真的试图简化这段代码

I have multiple processes (of different types) performed by multiple Runnable.我有多个 Runnable 执行的多个进程(不同类型)。

I'm trying to simplify this situation with a diagram.我试图用图表来简化这种情况。

在此处输入图片说明

I have a RunnableProducer producing with its time, the produced is transfer to a RunnableWorker that performs some operation ProcessorDown ( blue arrow ) performs a process, and distributes it to its recipients (of the same kind of class).我有一个RunnableProducer产生它的时间,产生的被转移到一个RunnableWorker执行一些操作ProcessorDown蓝色箭头)执行一个过程,并将其分发给它的接收者(同种类)。 If the RunnableWorker is marked ( code other than null), it must perform a special type of process Processor and return it to the "parent" RunnableWorker , who transferred it.如果RunnableWorker被标记(非空code ),它必须执行一种特殊类型的进程Processor并将其返回给“父” RunnableWorker ,后者将其转移。 That is, your receiver collects many performing another additional ProcessorUp ( green arrow ) Note the numbers of green arrows .也就是说,您的接收器收集了许多执行另一个额外ProcessorUp绿色箭头)的操作。请注意绿色箭头的数量 The initial RunnableWorker transfers (with the help of intermediaries of the same class) all the data to the RunnableConsumer without mixing them, who will perform another task (for this question, print ).最初的RunnableWorker将所有数据传输(在同一类的中介的帮助下)没有混合它们的RunnableConsumer ,后者将执行另一个任务(对于这个问题, print )。

The RunnableProducer should only produce when the RunnableConsumer can finally receive / collect everything produced (transferred by RunnableWorker's ). RunnableProducer应该只在RunnableConsumer最终可以接收/收集所有产生的东西时才产生(由RunnableWorker's传输)。 The RunnableProducer can be turned off independently. RunnableProducer可以独立关闭。 However, the RunnableConsumer must run while the RunnableProducer is producing until he has consumed everything (and its variants).但是, RunnableConsumer必须在RunnableProducer生产时运行,直到他消费完所有东西(及其变体)。

NOTE: You can copy, paste, compile and run注意:您可以复制、粘贴、编译和运行

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


public class TestCollectorRunnable1 {

  public static void main(String... args) {

    ExecutorService executorService = Executors.newCachedThreadPool();

    Counter counter = new Counter();
    LifeCycle rcLifeCycle = new LifeCycle();
    LifeCycle rpLifeCycle = new LifeCycle();

    RunnableConsumer rc = new RunnableConsumer("rc", rcLifeCycle, rpLifeCycle, executorService, counter);
    RunnableProducer rp = new RunnableProducer("rp", rpLifeCycle, rcLifeCycle, executorService, counter);
    RunnableWorker rw0 = new RunnableWorker("rw0", executorService, counter, null, null, rp.getOutBlockingQueue(), rc.getInBlockingQueue());

    RunnableWorker rw11 = new RunnableWorker("rw11", executorService, counter, null, rw0);
    RunnableWorker rw12 = new RunnableWorker("rw12", executorService, counter, null, rw0);
    rw0.addBlockingQueue(rw11.getInputBlockingQueue());
    rw0.addBlockingQueue(rw12.getInputBlockingQueue());

    RunnableWorker rw211 = new RunnableWorker("rw211", executorService, counter, 1, rw11);
    RunnableWorker rw212 = new RunnableWorker("rw212", executorService, counter, 2, rw11);
    RunnableWorker rw213 = new RunnableWorker("rw213", executorService, counter, 3, rw11);
    rw11.addBlockingQueue(rw211.getInputBlockingQueue());
    rw11.addBlockingQueue(rw212.getInputBlockingQueue());
    rw11.addBlockingQueue(rw213.getInputBlockingQueue());

    RunnableWorker rw221 = new RunnableWorker("rw221", executorService, counter, 4, rw12);
    RunnableWorker rw222 = new RunnableWorker("rw222", executorService, counter, 5, rw12);
    rw12.addBlockingQueue(rw221.getInputBlockingQueue());
    rw12.addBlockingQueue(rw222.getInputBlockingQueue());

    //Simulate Turn off
    new Timer().schedule(new TimerTask() {
      @Override
      public void run() {
        rp.stop();
      }
    }, ThreadLocalRandom.current().nextLong(100L, 1000L));

  }

  public static String getRandomString(int size) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < size; i++) {
      char c = (char) (new Random().nextInt(25) + 'a');
      sb.append(c);
    }
    return sb.toString();
  }

  public static class RunnableProducer implements Runnable {

    private final String name;
    private final LifeCycle ownLifeCycle;
    private final LifeCycle outLifeCycle;
    private final ExecutorService executorService;
    private final Counter counter;
    private final int bufferSize;
    private final BlockingQueue<ChunkDTO> outBlockingQueue;
    private volatile boolean isRunning = false;

    public RunnableProducer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, ExecutorService executorService, Counter counter) {
      this(name, ownLifeCycle, outLifeCycle, executorService, counter, new SynchronousQueue/*LinkedBlockingQueue*/<>());
    }

    public RunnableProducer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, ExecutorService executorService, Counter counter, BlockingQueue<ChunkDTO> outBlockingQueue) {
      this.name = name;
      this.ownLifeCycle = ownLifeCycle;
      this.outLifeCycle = outLifeCycle;
      this.executorService = executorService;
      this.counter = counter;
      this.bufferSize = 8;
      this.outBlockingQueue = outBlockingQueue;
      this.ownLifeCycle.setCreated(true);
      this.executorService.execute(this);
    }

    @Override
    public void run() {
      long quantity = 0;
      isRunning = true;

      //Blocking Wait (not very elegant) 
      /*
      block until the consumer can consume without losing what is produced and processed
       */
      while (!outLifeCycle.isRunning()) {
        try {
          Thread.sleep(10);
        } catch (Exception e) {
        }
      }

      while (/*isRunning*/quantity < 5) {
        ownLifeCycle.setRunning(true);
        try {
          byte[] outBytesSamples = getRandomString(bufferSize).getBytes();
          ChunkDTO chunkDTO = new ChunkDTO(outBytesSamples, quantity, null);
          outBlockingQueue.put(chunkDTO);
          System.out.println(name + ".Produced " + new String(outBytesSamples) + "\t index:" + quantity);
          int timeSleeping = ThreadLocalRandom.current().nextInt(10, 100);
          Thread.sleep(timeSleeping);
        } catch (Exception e) {
        }
        quantity++;
        counter.setValue(quantity);
      }
      System.out.println(name + "\tSent:" + quantity);
    }

    public BlockingQueue<ChunkDTO> getOutBlockingQueue() {
      return outBlockingQueue;
    }

    public void stop() {
      isRunning = false;
    }

  }

  public static class RunnableConsumer implements Runnable {

    private final String name;
    private final LifeCycle ownLifeCycle;
    private final LifeCycle outLifeCycle;
    private final ExecutorService executorService;
    private final Counter counter;
    private final BlockingQueue<ChunkDTO> inBlockingQueue;

    public RunnableConsumer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, ExecutorService executorService, Counter counter) {
      this(name, ownLifeCycle, outLifeCycle, executorService, counter, new SynchronousQueue/*LinkedBlockingQueue*/<>());
    }

    public RunnableConsumer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, ExecutorService executorService, Counter counter, BlockingQueue<ChunkDTO> inBlockingQueue) {
      this.name = name;
      this.ownLifeCycle = ownLifeCycle;
      this.outLifeCycle = outLifeCycle;
      this.executorService = executorService;
      this.counter = counter;
      this.inBlockingQueue = inBlockingQueue;
      this.ownLifeCycle.setCreated(true);
      this.executorService.execute(this);
    }

    @Override
    public void run() {
      if (inBlockingQueue != null) {
        try {
          int quantity = 0;
          while (!outLifeCycle.isCreated() || outLifeCycle.isRunning()/*haya recolectado lo que tiene que recolectar*/) {
            ownLifeCycle.setRunning(true);
            ChunkDTO chunkDTO = inBlockingQueue.take();
            System.out.println(name + ".Collected " + new String(chunkDTO.getChunk()) + "\t index:" + chunkDTO.getIndex() + "\t pitch:" + chunkDTO.getPitch());
            quantity++;
          }
          System.out.println(name + "\tReceived:" + quantity);
        } catch (InterruptedException e) {
        }
      }
    }

    public BlockingQueue<ChunkDTO> getInBlockingQueue() {
      return inBlockingQueue;
    }

  }

  public static class RunnableWorker {

    private final ExecutorService executorService;
    private final RunnableWorker parent;
    private final BlockingQueue<ChunkDTO> inputBlockingQueue;
    private final BlockingQueue<ChunkDTO> outputBlockingQueue;
    private final List<BlockingQueue<ChunkDTO>> downList;
    private final List<BlockingQueue<ChunkDTO>> upList;
    private final Set<Integer> codes;

    public RunnableWorker(String name, ExecutorService executorService, Counter counter, Integer code, RunnableWorker parent, BlockingQueue<ChunkDTO> inputBlockingQueue, BlockingQueue<ChunkDTO> outputBlockingQueue) {
      this.executorService = executorService;
      this.parent = parent;
      this.inputBlockingQueue = inputBlockingQueue;
      this.outputBlockingQueue = outputBlockingQueue;
      this.downList = new ArrayList<>();
      this.upList = new ArrayList<>(Arrays.asList(new SynchronousQueue/*LinkedBlockingQueue*/<>()));
      this.codes = new HashSet<>();

      //RUNNABLE DISTRIBUTOR
      this.executorService.execute(() -> {
        if (inputBlockingQueue != null) {
          try {
            while (true) {
              ChunkDTO chunkDTO = inputBlockingQueue.take();
              /*
              if (codes.size() > 0) {
                System.out.println(name + " codes.length:" + codes.size());
              }
              if (parent == null) {
                System.out.println(name + ".Worked " + new String(chunkDTO.getChunk()) + "\tindex:" + chunkDTO.getIndex());
              }
              // */
              if (code == null) {
                new ProcessorDown(executorService, chunkDTO, downList);
              } else {
                ChunkDTO returned = new ChunkDTO(chunkDTO.getChunk(), chunkDTO.getIndex(), code);
                System.out.println("\t\t" + name + ".Returned " + returned.toString());
                if (parent != null) {
                  new Processor(executorService, returned, parent.getUpList());
                  parent.addCodeSon(code);
                }
              }
            }
          } catch (Exception e) {
          }
        }
      });

      //RUNNABLE COLLECTOR
      if (code == null) {
        this.executorService.execute(() -> {
          int quantity = 0;
          while (quantity == 0) {
            BlockingQueue<ChunkDTO> outBlockingQueue = upList.get(0);
            if (outBlockingQueue != null) {
              try {
                while (quantity == 0 || (quantity > 0 && quantity < codes.size() * (counter.getValue()))) {
                  ChunkDTO chunkDTO = outBlockingQueue.take();
                  /*
                  System.out.println("\t" + name + ".quantity: " + quantity + ", codes.size():" + codes.size() + ", counter.getValue():" + counter.getValue() + ", total:" + (codes.size() * counter.getValue())
                      + "\r\t\tcchunk:" + chunkDTO
                      + "\r\t\tcodes:" + codes.stream().map(i -> i.toString()).collect(Collectors.joining(",")));
                  // */
                  if (chunkDTO != null) {
                    if (parent == null) {
                      outputBlockingQueue.put(chunkDTO);
                      System.out.println("\t\t" + name + ".Collected " + chunkDTO.toString());
                    } else {
                      new ProcessorUp(executorService, chunkDTO, parent.getUpList());
                    }
                    quantity++;
                  }
                }
                /*
                if (quantity != 0) {
                  String codesString = codes.stream().map(i -> i.toString()).collect(Collectors.joining(","));
                  System.out.println("\t" + name + "\tWorked:" + quantity + ", \tcodes:" + codesString);
                }
                // */
              } catch (InterruptedException e) {
              }
            }
          }
        });
      }
    }

    public void addCodeSon(Integer code) {
      if (parent != null) {
        parent.addCodeSon(code);
      }
      codes.add(code);
    }

    public RunnableWorker(String name, ExecutorService executorService, Counter counter, Integer code, RunnableWorker parent) {
      this(name, executorService, counter, code, parent, new SynchronousQueue/*LinkedBlockingQueue*/<>(), new SynchronousQueue/*LinkedBlockingQueue*/<>());
    }

    public BlockingQueue<ChunkDTO> getInputBlockingQueue() {
      return inputBlockingQueue;
    }

    public void addBlockingQueue(BlockingQueue<ChunkDTO> blockingQueue) {
      downList.add(blockingQueue);
    }

    public void delBlockingQueue(BlockingQueue<ChunkDTO> blockingQueue) {
      downList.remove(blockingQueue);
    }

    public List<BlockingQueue<ChunkDTO>> getUpList() {
      return upList;
    }

  }

  public static class Processor implements Runnable {

    private final ExecutorService executorService;
    private final List<BlockingQueue<ChunkDTO>> listOutput;
    private final ChunkDTO inChunkDTO;

    public Processor(ExecutorService executorService, ChunkDTO inChunkDTO, List<BlockingQueue<ChunkDTO>> listOutput) {
      this.executorService = executorService;
      this.listOutput = listOutput;
      this.inChunkDTO = inChunkDTO;
      this.executorService.execute(this);
    }

    @Override
    public void run() {
      if (inChunkDTO != null) {
        try {
          byte[] outBytes = internalProcessing(inChunkDTO.getChunk());
          ChunkDTO outChunkDTO = new ChunkDTO(outBytes, inChunkDTO.getIndex(), inChunkDTO.getPitch());
          if (listOutput != null) {
            listOutput.forEach(output -> {
              try {
                output.put(outChunkDTO);
              } catch (Exception e) {
              }
            });
          }
        } catch (Exception e) {
        }
      }

    }
  }

  public static class ProcessorDown extends Processor {

    public ProcessorDown(ExecutorService executorService, ChunkDTO inChunkDTO, List<BlockingQueue<ChunkDTO>> listOutput) {
      super(executorService, inChunkDTO, listOutput);
    }
  }

  public static class ProcessorUp extends Processor {

    public ProcessorUp(ExecutorService executorService, ChunkDTO inChunkDTO, List<BlockingQueue<ChunkDTO>> listOutput) {
      super(executorService, inChunkDTO, listOutput);
    }
  }

  private static byte[] internalProcessing(byte[] in) {
    byte[] out = in;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
    }
    return out;
  }

  public static class ChunkDTO {

    private final byte[] chunk;
    private final long index;
    private final Integer pitch;

    public ChunkDTO(byte[] chunk, long index, Integer pitch) {
      this.chunk = chunk;
      this.index = index;
      this.pitch = pitch;
    }

    public byte[] getChunk() {
      return chunk;
    }

    public long getIndex() {
      return index;
    }

    public Integer getPitch() {
      return pitch;
    }

    @Override
    public String toString() {
      return "ChunkDTO{" + "chunk=" + new String(chunk) + ", index=" + index + ", pitch=" + pitch + '}';
    }

  }

  public static class Counter {

    private final ReadWriteLock rwLock;
    private Long value;

    public Counter() {
      this.rwLock = new ReentrantReadWriteLock();
      this.value = 0L;
    }

    public Long getValue() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return value;
      } finally {
        readLock.unlock();
      }

    }

    public void setValue(Long value) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.value = value;
      } finally {
        writeLock.unlock();
      }
    }

  }

  public static class LifeCycle {

    private final ReadWriteLock rwLock;
    private boolean created;
    private boolean running;
    private boolean finished;

    public LifeCycle() {
      this.rwLock = new ReentrantReadWriteLock();
    }

    public boolean isCreated() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return created;
      } finally {
        readLock.unlock();
      }
    }

    public void setCreated(boolean created) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.created = created;
      } finally {
        writeLock.unlock();
      }
    }

    public boolean isRunning() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return running;
      } finally {
        readLock.unlock();
      }
    }

    public void setRunning(boolean running) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.running = running;
      } finally {
        writeLock.unlock();
      }
    }

    public boolean isFinished() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return finished;
      } finally {
        readLock.unlock();
      }
    }

    public void setFinished(boolean finished) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.finished = finished;
      } finally {
        writeLock.unlock();
      }
    }

  }

}

The class ChunkDTO contains the data, the index (position), and code ( to facilitate its classification by the RunnableConsumer ).ChunkDTO包含数据、索引(位置)和代码(便于RunnableConsumer对其进行分类)。

The Counter class in order to have control of what the RunnableConsumer/RunnableWorker should expect. Counter类可以控制RunnableConsumer/RunnableWorker应该期待什么。

If the RunnableProducer produces 7, and there are 5 codes, the RunnableConsumer should collect 35 finally.如果RunnableProducer产生 7 个,并且有 5 个代码,那么RunnableConsumer最终应该收集 35 个。 The rw11 RunnableWorker should collect 3*7=21 and The rw12 RunnableWorker should collect 2*7=14 . rw11 RunnableWorker应该收集3*7=21并且rw12 RunnableWorker应该收集2*7=14

The LifeCycle class was created in order to have control of LifeCycle Producer and Consumer, I still haven't logic for RunnableWorker .创建LifeCycle类是为了控制 LifeCycle Producer 和 Consumer,我仍然没有RunnableWorker逻辑。

The RunnableWorker has two Runnable, in order to handle to Transfer their children ( //RUNNABLE DISTRIBUTOR ) and parents ( //RUNNABLE COLLECTOR ). RunnableWorker有两个 Runnable,为了处理转移他们的孩子( //RUNNABLE DISTRIBUTOR )和父母( //RUNNABLE COLLECTOR )。

THE OUTPUT输出

rp.Produced tpwqomrt     index:0
rw0.Worked tpwqomrt index:0
        rw221.Returned ChunkDTO{chunk=tpwqomrt, index=0, pitch=4}
        rw222.Returned ChunkDTO{chunk=tpwqomrt, index=0, pitch=5}
        rw212.Returned ChunkDTO{chunk=tpwqomrt, index=0, pitch=2}
        rw213.Returned ChunkDTO{chunk=tpwqomrt, index=0, pitch=3}
        rw211.Returned ChunkDTO{chunk=tpwqomrt, index=0, pitch=1}
rp.Produced xwnlpkju     index:1
rw0 codes.length:5
rw0.Worked xwnlpkju index:1
rw11 codes.length:3
rw12 codes.length:2
        rw0.Collected ChunkDTO{chunk=tpwqomrt, index=0, pitch=2}
rc.Collected tpwqomrt    index:0     pitch:2
rc.Collected tpwqomrt    index:0     pitch:4
        rw0.Collected ChunkDTO{chunk=tpwqomrt, index=0, pitch=4}
        rw0.Collected ChunkDTO{chunk=tpwqomrt, index=0, pitch=1}
rc.Collected tpwqomrt    index:0     pitch:1
rc.Collected tpwqomrt    index:0     pitch:3
        rw0.Collected ChunkDTO{chunk=tpwqomrt, index=0, pitch=3}
        rw0.Collected ChunkDTO{chunk=tpwqomrt, index=0, pitch=5}
rc.Collected tpwqomrt    index:0     pitch:5
        rw212.Returned ChunkDTO{chunk=xwnlpkju, index=1, pitch=2}
        rw221.Returned ChunkDTO{chunk=xwnlpkju, index=1, pitch=4}
        rw222.Returned ChunkDTO{chunk=xwnlpkju, index=1, pitch=5}
        rw213.Returned ChunkDTO{chunk=xwnlpkju, index=1, pitch=3}
        rw211.Returned ChunkDTO{chunk=xwnlpkju, index=1, pitch=1}
rp.Produced xmdfcmmo     index:2
rw0 codes.length:5
rw0.Worked xmdfcmmo index:2
rw12 codes.length:2
rw11 codes.length:3
        rw221.Returned ChunkDTO{chunk=xmdfcmmo, index=2, pitch=4}
        rw212.Returned ChunkDTO{chunk=xmdfcmmo, index=2, pitch=2}
        rw222.Returned ChunkDTO{chunk=xmdfcmmo, index=2, pitch=5}
        rw213.Returned ChunkDTO{chunk=xmdfcmmo, index=2, pitch=3}
        rw211.Returned ChunkDTO{chunk=xmdfcmmo, index=2, pitch=1}
rw0 codes.length:5
rp.Produced syqpyxuk     index:3
rw0.Worked syqpyxuk index:3
rw11 codes.length:3
rw0 codes.length:5
rw0.Worked linlkasp index:4
rp.Produced linlkasp     index:4
rw12 codes.length:2
        rw211.Returned ChunkDTO{chunk=syqpyxuk, index=3, pitch=1}
        rw213.Returned ChunkDTO{chunk=syqpyxuk, index=3, pitch=3}
        rw212.Returned ChunkDTO{chunk=syqpyxuk, index=3, pitch=2}
rw11 codes.length:3
        rw222.Returned ChunkDTO{chunk=syqpyxuk, index=3, pitch=5}
        rw221.Returned ChunkDTO{chunk=syqpyxuk, index=3, pitch=4}
rw12 codes.length:2
        rw211.Returned ChunkDTO{chunk=linlkasp, index=4, pitch=1}
        rw213.Returned ChunkDTO{chunk=linlkasp, index=4, pitch=3}
        rw222.Returned ChunkDTO{chunk=linlkasp, index=4, pitch=5}
        rw212.Returned ChunkDTO{chunk=linlkasp, index=4, pitch=2}
        rw221.Returned ChunkDTO{chunk=linlkasp, index=4, pitch=4}
rp  Sent:5

As you can see, The Producer Sent 5 chunks , but I losses the majority, I need to receive 25 (for this example).如您所见,生产者发送了 5 个块,但我输了大部分,我需要接收 25 个(对于此示例)。 Only few items was collected by the Consumer.消费者只收集了很少的物品。 What is the problem with my logic?我的逻辑有什么问题?

I don't know if creating two runnable is a good solution for the RunnableWorker class.不知道为RunnableWorker类创建两个runnable是不是一个好的解决方案。 Is there any better implementation?有没有更好的实现?

I recognize that I have a horrible method of blocking the Producer to wait for the Consumer.我认识到我有一种可怕的方法来阻止生产者等待消费者。 What solution do you recommend?你推荐什么解决方案?

My own Answer我自己的答案

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TestCollectorRunnable7a {

  public static void main(String... args) {

    List<Future<?>> futureList = new ArrayList<>();
    ExecutorService executorService = Executors.newCachedThreadPool();

    Counter counter = new Counter();
    CodesList codesList = new CodesList();
    LifeCycle rcLifeCycle = new LifeCycle();
    LifeCycle rpLifeCycle = new LifeCycle();

    RunnableConsumer rc = new RunnableConsumer("rc", rcLifeCycle, rpLifeCycle, futureList, executorService, counter, codesList);
    RunnableProducer rp = new RunnableProducer("rp", rpLifeCycle, rcLifeCycle, futureList, executorService, counter);
    RunnableWorker rw0 = new RunnableWorker("rw0", rcLifeCycle, futureList, executorService, counter, codesList, null, null, rp.getOutBlockingQueue(), rc.getInBlockingQueue());

    RunnableWorker rw11 = new RunnableWorker("rw11", rcLifeCycle, futureList, executorService, counter, codesList, null, rw0);
    RunnableWorker rw12 = new RunnableWorker("rw12", rcLifeCycle, futureList, executorService, counter, codesList, null, rw0);
    rw0.addBlockingQueue(rw11.getInputBlockingQueue());
    rw0.addBlockingQueue(rw12.getInputBlockingQueue());

    RunnableWorker rw211 = new RunnableWorker("rw211", rcLifeCycle, futureList, executorService, counter, codesList, 1, rw11);
    RunnableWorker rw212 = new RunnableWorker("rw212", rcLifeCycle, futureList, executorService, counter, codesList, 2, rw11);
    RunnableWorker rw213 = new RunnableWorker("rw213", rcLifeCycle, futureList, executorService, counter, codesList, 3, rw11);
    rw11.addBlockingQueue(rw211.getInputBlockingQueue());
    rw11.addBlockingQueue(rw212.getInputBlockingQueue());
    rw11.addBlockingQueue(rw213.getInputBlockingQueue());

    RunnableWorker rw221 = new RunnableWorker("rw221", rcLifeCycle, futureList, executorService, counter, codesList, 4, rw12);
    RunnableWorker rw222 = new RunnableWorker("rw222", rcLifeCycle, futureList, executorService, counter, codesList, 5, rw12);
    rw12.addBlockingQueue(rw221.getInputBlockingQueue());
    rw12.addBlockingQueue(rw222.getInputBlockingQueue());

    //Simulate Turn off
    new Timer(false).schedule(new TimerTask() {
      @Override
      public void run() {
        rp.stop();
      }
    }, ThreadLocalRandom.current().nextLong(100L, 1000L));
  }

  public static String getRandomString(int size) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < size; i++) {
      char c = (char) (new Random().nextInt(25) + 'a');
      sb.append(c);
    }
    return sb.toString();
  }

  public static class RunnableProducer implements Runnable {

    private final String name;
    private final LifeCycle ownLifeCycle;
    private final LifeCycle outLifeCycle;
    private final List<Future<?>> futureList;
    private final ExecutorService executorService;
    private final Counter counter;
    private final int bufferSize;
    private final BlockingQueue<ChunkDTO> outBlockingQueue;
    private volatile boolean isRunning = false;

    public RunnableProducer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, List<Future<?>> futureList, ExecutorService executorService, Counter counter) {
      this(name, ownLifeCycle, outLifeCycle, futureList, executorService, counter, new LinkedBlockingQueue<>());
    }

    public RunnableProducer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, List<Future<?>> futureList, ExecutorService executorService, Counter counter, BlockingQueue<ChunkDTO> outBlockingQueue) {
      this.name = name;
      this.ownLifeCycle = ownLifeCycle;
      this.outLifeCycle = outLifeCycle;
      this.futureList = futureList;
      this.executorService = executorService;
      this.counter = counter;
      this.bufferSize = 8;
      this.outBlockingQueue = outBlockingQueue;
      this.ownLifeCycle.setCreated(true);
      this.futureList.add(this.executorService.submit(this));

    }

    @Override
    public void run() {
      long quantity = 0;
      while (!outLifeCycle.isRunning()) {
        try {
          Thread.sleep(100);
        } catch (Exception ex) {
          Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
        }
      }

      isRunning = true;
      ownLifeCycle.setRunning(true);
      while (isRunning) {
        try {
          byte[] outBytesSamples = getRandomString(bufferSize).getBytes();
          ChunkDTO chunkDTO = new ChunkDTO(outBytesSamples, quantity, null);
          outBlockingQueue.put(chunkDTO);
          System.out.println(name + ".Produced " + new String(outBytesSamples) + "\t index:" + quantity);
          int timeSleeping = ThreadLocalRandom.current().nextInt(10, 100);
          Thread.sleep(timeSleeping);
        } catch (Exception ex) {
          Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
        }
        quantity++;
        counter.setValue(quantity);
      }
      ownLifeCycle.setRunning(false);
      System.out.println(name + "\tSent:" + quantity);
      ownLifeCycle.setFinished(true);
    }

    public BlockingQueue<ChunkDTO> getOutBlockingQueue() {
      return outBlockingQueue;
    }

    public void stop() {
      isRunning = false;
    }

  }

  public static class RunnableConsumer implements Runnable {

    private final String name;
    private final LifeCycle ownLifeCycle;
    private final LifeCycle outLifeCycle;
    private final List<Future<?>> futureList;
    private final ExecutorService executorService;
    private final Counter counter;
    private final Counter intCounter;
    private final CodesList codesList;
    private final BlockingQueue<ChunkDTO> inBlockingQueue;

    public RunnableConsumer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, List<Future<?>> futureList, ExecutorService executorService, Counter counter, CodesList codesList) {
      this(name, ownLifeCycle, outLifeCycle, futureList, executorService, counter, new LinkedBlockingQueue/*SynchronousQueue LinkedBlockingQueue*/<>(), codesList);
    }

    public RunnableConsumer(String name, LifeCycle ownLifeCycle, LifeCycle outLifeCycle, List<Future<?>> futureList, ExecutorService executorService, Counter counter, BlockingQueue<ChunkDTO> inBlockingQueue, CodesList codesList) {
      this.name = name;
      this.ownLifeCycle = ownLifeCycle;
      this.outLifeCycle = outLifeCycle;
      this.futureList = futureList;
      this.executorService = executorService;
      this.counter = counter;
      this.inBlockingQueue = inBlockingQueue;
      this.intCounter = new Counter();
      this.codesList = codesList;
      this.ownLifeCycle.setCreated(true);

      this.futureList.add(this.executorService.submit(() -> {
        while (!this.outLifeCycle.isFinished() || intCounter.getValue() < counter.getValue() * codesList.size()) {
          try {
            Thread.sleep(100);
          } catch (InterruptedException ex) {
            Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
        inBlockingQueue.add(new ChunkStopper(null, -1, null));
      }));
      this.futureList.add(this.executorService.submit(this));
    }

    @Override
    public void run() {
      if (inBlockingQueue != null) {
        try {
          long quantity = 0;
          ownLifeCycle.setRunning(true);
          while (true) {
            ChunkDTO chunkDTO = inBlockingQueue.take();
            if (chunkDTO instanceof ChunkStopper) {
              ownLifeCycle.setRunning(false);
              break;
            }
            System.out.println(name + ".Consumed " + new String(chunkDTO.getChunk()) + "\t index:" + chunkDTO.getIndex() + "\t code:" + chunkDTO.getPitch() + ", \tquantity:" + quantity);
            quantity++;
            intCounter.setValue(quantity);
          }
          ownLifeCycle.setRunning(false);
          System.out.println(name + "\tReceived:" + quantity);
          ownLifeCycle.setFinished(true);
        } catch (InterruptedException ex) {
          Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
    }

    public BlockingQueue<ChunkDTO> getInBlockingQueue() {
      return inBlockingQueue;
    }

  }

  public static class RunnableWorker {

    private final LifeCycle ownLifeCycle;
    private final LifeCycle outLifeCycle;
    private final List<Future<?>> futureList;
    private final ExecutorService executorService;
    private final Counter intCounter;
    private final CodesList codesList;
    private final RunnableWorker parent;
    private final BlockingQueue<ChunkDTO> inputBlockingQueue;
    private final BlockingQueue<ChunkDTO> outputBlockingQueue;
    private final List<BlockingQueue<ChunkDTO>> downList;
    private final List<BlockingQueue<ChunkDTO>> upList;
    private final Set<Integer> codes;

    public RunnableWorker(String name, LifeCycle outLifeCycle, List<Future<?>> futureList, ExecutorService executorService, Counter counter, CodesList codesList, Integer code, RunnableWorker parent, BlockingQueue<ChunkDTO> inputBlockingQueue, BlockingQueue<ChunkDTO> outputBlockingQueue) {
      this.ownLifeCycle = new LifeCycle();
      this.outLifeCycle = outLifeCycle;
      this.futureList = futureList;
      this.executorService = executorService;
      this.intCounter = new Counter();
      this.codesList = codesList;
      this.parent = parent;
      this.inputBlockingQueue = inputBlockingQueue;
      this.outputBlockingQueue = outputBlockingQueue;
      this.downList = new ArrayList<>();
      this.upList = new ArrayList<>(Arrays.asList(new LinkedBlockingQueue<>()));
      this.codes = new HashSet<>();

      if (code != null) {
        this.codesList.addCode(code);
      }

      this.futureList.add(this.executorService.submit(() -> {
        while (!outLifeCycle.isFinished()) {
          try {
            Thread.sleep(200);
          } catch (InterruptedException ex) {
            Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
        //System.out.println(name + " -> Consumer Finished!");
        while (true) {
          try {
            BlockingQueue<ChunkDTO> outBlockingQueue = upList.get(0);
            outBlockingQueue.add(new ChunkStopper(null, -1, null));
            break;
          } catch (Exception ex) {
            Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
        while (true) {
          try {
            inputBlockingQueue.add(new ChunkStopper(null, -1, null));
            break;
          } catch (Exception ex) {
            Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
      }));

      //RUNNABLE DISTRIBUTOR
      this.futureList.add(this.executorService.submit(() -> {
        long quantity = 0;
        if (inputBlockingQueue != null) {
          try {
            ownLifeCycle.setRunning(true);
            while (true) {
              ChunkDTO chunkDTO = inputBlockingQueue.take();
              if (chunkDTO instanceof ChunkStopper) {
                break;
              }
              if (code == null) {
                new ProcessorDown(futureList, executorService, chunkDTO, downList);
              } else {
                ChunkDTO returned = new ChunkDTO(chunkDTO.getChunk(), chunkDTO.getIndex(), code);
                //System.out.println("\t\t" + name + ".Returned " + returned.toString());
                if (parent != null) {
                  new Processor(this.futureList, executorService, returned, parent.getUpList());
                  parent.addCodeSon(code);
                }
              }
              quantity++;
              intCounter.setValue(quantity);
            }
            ownLifeCycle.setRunning(false);
          } catch (Exception ex) {
            Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
        //System.out.println(name + ". DISTRIBUTOR Finished");
      }));

      //RUNNABLE COLLECTOR
      if (code == null) {
        this.futureList.add(this.executorService.submit(() -> {
          int quantity = 0;
          while (quantity == 0) {
            BlockingQueue<ChunkDTO> outBlockingQueue = upList.get(0);
            if (outBlockingQueue != null) {
              try {
                while (true) {
                  ChunkDTO chunkDTO = outBlockingQueue.take();
                  if (chunkDTO instanceof ChunkStopper) {
                    break;
                  }
                  if (parent == null) {
                    outputBlockingQueue.put(chunkDTO);
                    //System.out.println("\t\t" + name + ".Collected " + chunkDTO.toString());
                  } else {
                    new ProcessorUp(futureList, executorService, chunkDTO, parent.getUpList());
                  }
                  quantity++;
                }
              } catch (InterruptedException ex) {
                Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
              }
            }
          }
          //System.out.println(name + ". COLLECTOR Finished");
        }));
      }
    }

    public LifeCycle getOwnLifeCycle() {
      return ownLifeCycle;
    }

    public void addCodeSon(Integer code) {
      if (parent != null) {
        parent.addCodeSon(code);
      }
      codes.add(code);
    }

    public RunnableWorker(String name, LifeCycle outLifeCycle, List<Future<?>> futureList, ExecutorService executorService, Counter counter, CodesList codesList, Integer code, RunnableWorker parent) {
      this(name, outLifeCycle, futureList, executorService, counter, codesList, code, parent, new LinkedBlockingQueue<>(), new LinkedBlockingQueue<>());
    }

    public BlockingQueue<ChunkDTO> getInputBlockingQueue() {
      return inputBlockingQueue;
    }

    public void addBlockingQueue(BlockingQueue<ChunkDTO> blockingQueue) {
      downList.add(blockingQueue);
    }

    public List<BlockingQueue<ChunkDTO>> getUpList() {
      return upList;
    }

  }

  public static class Processor implements Runnable {

    private final ExecutorService executorService;
    private final List<BlockingQueue<ChunkDTO>> listOutput;
    private final ChunkDTO inChunkDTO;

    public Processor(List<Future<?>> futureList, ExecutorService executorService, ChunkDTO inChunkDTO, List<BlockingQueue<ChunkDTO>> listOutput) {
      this.executorService = executorService;
      this.listOutput = listOutput;
      this.inChunkDTO = inChunkDTO;
      futureList.add(this.executorService.submit(this));
    }

    @Override
    public void run() {
      if (inChunkDTO != null) {
        try {
          byte[] outBytes = internalProcessing(inChunkDTO.getChunk());
          ChunkDTO outChunkDTO = new ChunkDTO(outBytes, inChunkDTO.getIndex(), inChunkDTO.getPitch());
          if (listOutput != null) {
            listOutput.forEach(output -> {
              try {
                output.put(outChunkDTO);
              } catch (Exception ex) {
                Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
              }
            });
          }
        } catch (Exception ex) {
          Logger.getLogger(TestCollectorRunnable7a.class.getName()).log(Level.SEVERE, null, ex);
        }
      }

    }
  }

  public static class ProcessorDown extends Processor {

    public ProcessorDown(List<Future<?>> futureList, ExecutorService executorService, ChunkDTO inChunkDTO, List<BlockingQueue<ChunkDTO>> listOutput) {
      super(futureList, executorService, inChunkDTO, listOutput);
    }
  }

  public static class ProcessorUp extends Processor {

    public ProcessorUp(List<Future<?>> futureList, ExecutorService executorService, ChunkDTO inChunkDTO, List<BlockingQueue<ChunkDTO>> listOutput) {
      super(futureList, executorService, inChunkDTO, listOutput);
    }
  }

  private static byte[] internalProcessing(byte[] in) {
    byte[] out = in;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
    }
    return out;
  }

  public static class ChunkStopper extends ChunkDTO {

    public ChunkStopper(byte[] chunk, long index, Integer pitch) {
      super(chunk, index, pitch);
    }
  }

  public static class ChunkDTO {

    private final byte[] chunk;
    private final long index;
    private final Integer pitch;

    public ChunkDTO(byte[] chunk, long index, Integer pitch) {
      this.chunk = chunk;
      this.index = index;
      this.pitch = pitch;
    }

    public byte[] getChunk() {
      return chunk;
    }

    public long getIndex() {
      return index;
    }

    public Integer getPitch() {
      return pitch;
    }

    @Override
    public String toString() {
      return "ChunkDTO{" + "chunk=" + new String(chunk) + ", index=" + index + ", pitch=" + pitch + '}';
    }

  }

  public static class Counter {

    private final ReadWriteLock rwLock;
    private Long value;

    public Counter() {
      this.rwLock = new ReentrantReadWriteLock();
      this.value = 0L;
    }

    public Long getValue() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return value;
      } finally {
        readLock.unlock();
      }

    }

    public void setValue(Long value) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.value = value;
      } finally {
        writeLock.unlock();
      }
    }

  }

  public static class CodesList {

    private final List<Integer> codes;
    private final ReadWriteLock rwLock;

    public CodesList() {
      this.codes = new ArrayList<>();
      this.rwLock = new ReentrantReadWriteLock();
    }

    public void addCode(Integer code) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();

      try {
        codes.add(code);
      } finally {
        writeLock.unlock();
      }
    }

    public int size() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return codes.size();
      } finally {
        readLock.unlock();
      }
    }

  }

  public static class LifeCycle {

    private final ReadWriteLock rwLock;
    private boolean created;
    private boolean running;
    private boolean finished;

    public LifeCycle() {
      this.rwLock = new ReentrantReadWriteLock();
    }

    public boolean isCreated() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return created;
      } finally {
        readLock.unlock();
      }
    }

    public void setCreated(boolean created) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.created = created;
      } finally {
        writeLock.unlock();
      }
    }

    public boolean isRunning() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return running;
      } finally {
        readLock.unlock();
      }
    }

    public void setRunning(boolean running) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.running = running;
      } finally {
        writeLock.unlock();
      }
    }

    public boolean isFinished() {
      Lock readLock = rwLock.readLock();
      readLock.lock();
      try {
        return finished;
      } finally {
        readLock.unlock();
      }
    }

    public void setFinished(boolean finished) {
      Lock writeLock = rwLock.writeLock();
      writeLock.lock();
      try {
        this.finished = finished;
      } finally {
        writeLock.unlock();
      }
    }

  }

}

My test我的测试

rp.Produced egxjthjr     index:0
rp.Produced pdiutqkt     index:1
rc.Consumed egxjthjr     index:0     code:2,    quantity:0
rc.Consumed egxjthjr     index:0     code:1,    quantity:1
rc.Consumed egxjthjr     index:0     code:5,    quantity:2
rc.Consumed egxjthjr     index:0     code:3,    quantity:3
rc.Consumed egxjthjr     index:0     code:4,    quantity:4
rc.Consumed pdiutqkt     index:1     code:4,    quantity:5
rp.Produced dwqtvoun     index:2
rc.Consumed pdiutqkt     index:1     code:2,    quantity:6
rc.Consumed pdiutqkt     index:1     code:5,    quantity:7
rc.Consumed pdiutqkt     index:1     code:1,    quantity:8
rc.Consumed pdiutqkt     index:1     code:3,    quantity:9
rp.Produced ydwqheks     index:3
rc.Consumed dwqtvoun     index:2     code:4,    quantity:10
rc.Consumed dwqtvoun     index:2     code:5,    quantity:11
rc.Consumed dwqtvoun     index:2     code:1,    quantity:12
rc.Consumed dwqtvoun     index:2     code:2,    quantity:13
rc.Consumed dwqtvoun     index:2     code:3,    quantity:14
rc.Consumed ydwqheks     index:3     code:1,    quantity:15
rc.Consumed ydwqheks     index:3     code:3,    quantity:16
rc.Consumed ydwqheks     index:3     code:2,    quantity:17
rc.Consumed ydwqheks     index:3     code:5,    quantity:18
rc.Consumed ydwqheks     index:3     code:4,    quantity:19
rp.Produced tamvejvq     index:4
rp.Produced tpqjkgqd     index:5
rc.Consumed tamvejvq     index:4     code:4,    quantity:20
rc.Consumed tamvejvq     index:4     code:5,    quantity:21
rc.Consumed tamvejvq     index:4     code:2,    quantity:22
rc.Consumed tamvejvq     index:4     code:3,    quantity:23
rc.Consumed tamvejvq     index:4     code:1,    quantity:24
rp.Produced quchekol     index:6
rc.Consumed tpqjkgqd     index:5     code:4,    quantity:25
rc.Consumed tpqjkgqd     index:5     code:2,    quantity:26
rc.Consumed tpqjkgqd     index:5     code:5,    quantity:27
rc.Consumed tpqjkgqd     index:5     code:3,    quantity:28
rc.Consumed tpqjkgqd     index:5     code:1,    quantity:29
rc.Consumed quchekol     index:6     code:4,    quantity:30
rc.Consumed quchekol     index:6     code:1,    quantity:31
rc.Consumed quchekol     index:6     code:5,    quantity:32
rc.Consumed quchekol     index:6     code:2,    quantity:33
rc.Consumed quchekol     index:6     code:3,    quantity:34
rp  Sent:7
rc  Received:35

Another Test另一个测试

rp.Produced iufalvxu     index:0
rp.Produced ammjynnm     index:1
rc.Consumed iufalvxu     index:0     code:4,    quantity:0
rc.Consumed iufalvxu     index:0     code:2,    quantity:1
rc.Consumed iufalvxu     index:0     code:1,    quantity:2
rc.Consumed iufalvxu     index:0     code:5,    quantity:3
rc.Consumed iufalvxu     index:0     code:3,    quantity:4
rc.Consumed ammjynnm     index:1     code:1,    quantity:5
rc.Consumed ammjynnm     index:1     code:3,    quantity:6
rc.Consumed ammjynnm     index:1     code:4,    quantity:7
rc.Consumed ammjynnm     index:1     code:5,    quantity:8
rc.Consumed ammjynnm     index:1     code:2,    quantity:9
rp.Produced clbecbge     index:2
rc.Consumed clbecbge     index:2     code:1,    quantity:10
rc.Consumed clbecbge     index:2     code:4,    quantity:11
rc.Consumed clbecbge     index:2     code:3,    quantity:12
rc.Consumed clbecbge     index:2     code:5,    quantity:13
rc.Consumed clbecbge     index:2     code:2,    quantity:14
rp.Produced sletiovo     index:3
rc.Consumed sletiovo     index:3     code:5,    quantity:15
rc.Consumed sletiovo     index:3     code:1,    quantity:16
rc.Consumed sletiovo     index:3     code:2,    quantity:17
rc.Consumed sletiovo     index:3     code:4,    quantity:18
rc.Consumed sletiovo     index:3     code:3,    quantity:19
rp  Sent:4
rc  Received:20

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM