[英]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.