I have the producer code that generates the random character:
public class Producer implements Runnable {
#Override
public void run() {
Stream<Character> generate = Stream.generate(this::generateRandomCharacter).limit(15);
generate.forEach(character -> {
MyEvent myEvent = new MyEvent();
myEvent.setMesage(character + "");
LOG.info("Producer: " + name + " is waiting to transfer...");
try {
boolean added = transferQueue.tryTransfer(myEvent, 4000, TimeUnit.MILLISECONDS);
if (added) {
numberOfProducedMessages.incrementAndGet();
LOG.info("Producer: " + name + " transferred element: A");
} else {
LOG.info("can not add an element due to the timeout");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
The consumer code is provided:
public class Consumer implements Runnable {
private static final Logger LOG = Logger.getLogger(Consumer.class.getName());
private final TransferQueue<MyEvent> transferQueue;
private final String name;
final int numberOfMessagesToConsume;
final AtomicInteger numberOfConsumedMessages = new AtomicInteger();
Consumer(TransferQueue<MyEvent> transferQueue, String name, int numberOfMessagesToConsume) {
this.transferQueue = transferQueue;
this.name = name;
this.numberOfMessagesToConsume = numberOfMessagesToConsume;
}
#Override
public void run() {
while (true){
try {
LOG.info("Consumer: " + name + " is waiting to take element...");
MyEvent element = transferQueue.take();
longProcessing(element);
System.out.println("Consumer: " + name + " received element with messgae : " + element.getMesage());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void longProcessing(MyEvent element) throws InterruptedException {
numberOfConsumedMessages.incrementAndGet();
Thread.sleep(5);
}
}
This is the call for the consumer/ produce:
TransferQueue<Event> transferQueue = new LinkedTransferQueue<>();
ExecutorService exService = Executors.newFixedThreadPool(2);
Producer producer = new Producer( transferQueue, "1", 2);
Consumer consumer = new Consumer(transferQueue, "1", 2);
exService.execute(producer);
exService.execute(consumer);
boolean isShutDown = exService.awaitTermination(5000, TimeUnit.MILLISECONDS);
if (!isShutDown) {
exService.shutdown();
}
The producer will create only a limited number of characters that the consumer will consume. How do I know if the producer is finished the character generation?
I think about implementing a timeout to know if the producer is not sending any more characters, but there might be a better option for this implementation.
There are various alternative ways to achieve this:
Use a special type of event to show that the producer has finished. (This is basically what the answer by Krzysztof Cichocki suggests). Pros: simplicity. Cons: you have to make sure that whatever special event you choose to signify "finished" cannot possibly be a real event emitted by the producer.
Use a count. It looks like this is what your code is already trying to do. For example, pass 15 in the numberOfMessagesToConsume argument to the consumer constructor, and the Run() method then stops once it has consumed 15 messages. Pros: simplicity. Cons: inflexibility, and you might not know how many messages the producer will produce beforehand.
Monitor the state of the producer thread. For example, the consumer can check while (producerThread.isAlive()) {...}. The producer thread will terminate when it has finished producing the messages. Pros: flexibility. Cons: you don't want the consumer to know about the producer thread, as that's too much coupling. For example, you might start the producer using new Thread(...) or you might use an ExecutorService or a CompletableFuture. The consumer shouldn't need to know.
One way of mitigating around the disadvantage of option 3 is to pass a function to the consumer to decouple the testing of producer state from the threading details:
Constructor:
Consumer(TransferQueue<MyEvent> transferQueue, String name, BooleanSupplier isProducerStillProducing)
Call the constructor with a lambda:
new Consumer(transferQueue, name, () -> producerThread.isAlive())
Test it in the run() method:
while (isProducerStillProducing.getAsBoolean()) { ... }
You can just send from producer an event with a message eg. "finished".
And then in you consumer just check for this message to know the stream is finished.
The time out is not so good idea, because it might happen for different reasons than closing the stream.
Sometimes coordinating the shut-down of producer and consumer can be a very puzzling task. Sometimes it is easier in one programming language than another due to differences in syntax.
The following example written using the Ada programming language creates a producer and a consumer. The producer sends a series of characters to the consumer. The consumer prints each character as it is received. The consumer terminates when the producer terminates.
This example uses the Ada Rendezvous mechanism for communication between tasks (aka threads).
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task producer;
task consumer is
entry send (Item : in Character);
end consumer;
task body producer is
subtype lower is Character range 'a' .. 'z';
subtype upper is Character range 'A' .. 'Z';
begin
for C in lower loop
consumer.send (C);
delay 0.05;
end loop;
for C in upper loop
consumer.send (C);
delay 0.05;
end loop;
end producer;
task body consumer is
Char : Character;
begin
loop
select
accept send (Item : in Character) do
Char := Item;
end send;
Put (Char);
if Char = 'z' then
New_Line(2);
end if;
or
terminate;
end select;
end loop;
end consumer;
begin
null;
end Main;
The output of this program is:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Related
I have around 60 sockets and 20 threads and I want to make sure each thread works on different socket everytime so I don't want to share same socket between two threads at all.
In my SocketManager class, I have a background thread which runs every 60 seconds and calls updateLiveSockets() method. In the updateLiveSockets() method, I iterate all the sockets I have and then start pinging them one by one by calling send method of SendToQueue class and basis on the response I mark them as live or dead. In the updateLiveSockets() method, I always need to iterate all the sockets and ping them to check whether they are live or dead.
Now all the reader threads will call getNextSocket() method of SocketManager class concurrently to get the next live available socket to send the business message on that socket. So I have two types of messages which I am sending on a socket:
One is ping message on a socket. This is only sent from timer thread calling updateLiveSockets() method in SocketManager class.
Other is business message on a socket. This is done in SendToQueue class.
So if pinger thread is pinging a socket to check whether they are live or not then no other business thread should use that socket. Similarly if business thread is using a socket to send data on it, then pinger thread should not ping that socket. And this applies to all the socket. But I need to make sure that in updateLiveSockets method, we are pinging all the available sockets whenever my background thread starts so that we can figure out which socket is live or dead.
Below is my SocketManager class:
public class SocketManager {
private static final Random random = new Random();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final Map<Datacenters, List<SocketHolder>> liveSocketsByDatacenter =
new ConcurrentHashMap<>();
private final ZContext ctx = new ZContext();
// ...
private SocketManager() {
connectToZMQSockets();
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
updateLiveSockets();
}
}, 60, 60, TimeUnit.SECONDS);
}
// during startup, making a connection and populate once
private void connectToZMQSockets() {
Map<Datacenters, List<String>> socketsByDatacenter = Utils.SERVERS;
for (Map.Entry<Datacenters, List<String>> entry : socketsByDatacenter.entrySet()) {
List<SocketHolder> addedColoSockets = connect(entry.getValue(), ZMQ.PUSH);
liveSocketsByDatacenter.put(entry.getKey(), addedColoSockets);
}
}
private List<SocketHolder> connect(List<String> paddes, int socketType) {
List<SocketHolder> socketList = new ArrayList<>();
// ....
return socketList;
}
// this method will be called by multiple threads concurrently to get the next live socket
// is there any concurrency or thread safety issue or race condition here?
public Optional<SocketHolder> getNextSocket() {
for (Datacenters dc : Datacenters.getOrderedDatacenters()) {
Optional<SocketHolder> liveSocket = getLiveSocket(liveSocketsByDatacenter.get(dc));
if (liveSocket.isPresent()) {
return liveSocket;
}
}
return Optional.absent();
}
private Optional<SocketHolder> getLiveSocket(final List<SocketHolder> listOfEndPoints) {
if (!listOfEndPoints.isEmpty()) {
// The list of live sockets
List<SocketHolder> liveOnly = new ArrayList<>(listOfEndPoints.size());
for (SocketHolder obj : listOfEndPoints) {
if (obj.isLive()) {
liveOnly.add(obj);
}
}
if (!liveOnly.isEmpty()) {
// The list is not empty so we shuffle it an return the first element
return Optional.of(liveOnly.get(random.nextInt(liveOnly.size()))); // just pick one
}
}
return Optional.absent();
}
// runs every 60 seconds to ping all the available socket to make sure whether they are alive or not
private void updateLiveSockets() {
Map<Datacenters, List<String>> socketsByDatacenter = Utils.SERVERS;
for (Map.Entry<Datacenters, List<String>> entry : socketsByDatacenter.entrySet()) {
List<SocketHolder> liveSockets = liveSocketsByDatacenter.get(entry.getKey());
List<SocketHolder> liveUpdatedSockets = new ArrayList<>();
for (SocketHolder liveSocket : liveSockets) {
Socket socket = liveSocket.getSocket();
String endpoint = liveSocket.getEndpoint();
Map<byte[], byte[]> holder = populateMap();
Message message = new Message(holder, Partition.COMMAND);
// pinging to see whether a socket is live or not
boolean isLive = SendToQueue.getInstance().send(message.getAddress(), message.getEncodedRecords(), socket);
SocketHolder zmq = new SocketHolder(socket, liveSocket.getContext(), endpoint, isLive);
liveUpdatedSockets.add(zmq);
}
liveSocketsByDatacenter.put(entry.getKey(), Collections.unmodifiableList(liveUpdatedSockets));
}
}
}
And here is my SendToQueue class:
// this method will be called by multiple reader threads (around 20) concurrently to send the data
public boolean sendAsync(final long address, final byte[] encodedRecords) {
PendingMessage m = new PendingMessage(address, encodedRecords, true);
cache.put(address, m);
return doSendAsync(m);
}
private boolean doSendAsync(final PendingMessage pendingMessage) {
Optional<SocketHolder> liveSocket = SocketManager.getInstance().getNextSocket();
if (!liveSocket.isPresent()) {
// log error
return false;
}
ZMsg msg = new ZMsg();
msg.add(pendingMessage.getEncodedRecords());
try {
// send data on a socket LINE A
return msg.send(liveSocket.get().getSocket());
} finally {
msg.destroy();
}
}
public boolean send(final long address, final byte[] encodedRecords, final Socket socket) {
PendingMessage m = new PendingMessage(address, encodedRecords, socket, false);
cache.put(address, m);
try {
if (doSendAsync(m, socket)) {
return m.waitForAck();
}
return false;
} finally {
cache.invalidate(address);
}
}
Problem Statement
Now as you can see above that I am sharing same socket between two threads. It seems getNextSocket() in SocketManager class could return a 0MQ socket to Thread A. Concurrently, the timer thread may access the same 0MQ socket to ping it. In this case Thread A and the timer thread are mutating the same 0MQ socket, which can lead to problems. So I am trying to find a way so that I can prevent different threads from sending data to the same socket at the same time and mucking up my data.
One solution I can think of is using synchronization on a socket while sending the data but if many threads uses the same socket, resources aren't well utilized. Moreover If msg.send(socket); is blocked (technically it shouldn't) all threads waiting for this socket are blocked. So I guess there might be a better way to ensure that every thread uses a different single live socket at the same time instead of synchronization on a particular socket.
So I am trying to find a way so that I can prevent different threads from sending data to the same socket at the same time and mucking up my data.
There are certainly a number of different ways to do this. For me this seems like a BlockingQueue is the right thing to use. The business threads would take a socket from the queue and would be guaranteed that no one else would be using that socket.
private final BlockingQueue<SocketHolder> socketHolderQueue = new LinkedBlockingQueue<>();
...
public Optional<SocketHolder> getNextSocket() {
SocketHolder holder = socketHolderQueue.poll();
return holder;
}
...
public void finishedWithSocket(SocketHolder holder) {
socketHolderQueue.put(holder);
}
I think that synchronizing on the socket is not a good idea for the reasons that you mention – the ping thread will be blocking the business thread.
There are a number of ways of handling the ping thread logic. I would store your Socket with a last use time and then your ping thread could every so often take each of the sockets from the same BlockingQueue, test it, and put each back onto the end of the queue after testing.
public void testSockets() {
// one run this for as many sockets as are in the queue
int numTests = socketHolderQueue.size();
for (int i = 0; i < numTests; i++) {
SocketHolder holder = socketHolderQueue.poll();
if (holder == null) {
break;
}
if (socketIsOk(socketHolder)) {
socketHolderQueue.put(socketHolder);
} else {
// close it here or something
}
}
}
You could also have the getNextSocket() code that dequeues the threads from the queue check the timer and put them on a test queue for the ping thread to use and then take the next one from the queue. The business threads would never be using the same socket at the same time as the ping thread.
Depending on when you want to test the sockets, you can also reset the timer after the business thread returns it to the queue so the ping thread would test the socket after X seconds of no use.
It looks like you should consider using the try-with-resource feature here. You have the SocketHolder or Option class implement the AutoCloseable interface. For instance, let us assume that Option implements this interface. The Option close method will then add back the instance to the container. I created a simple example that shows what I mean. It is not complete but it gives you an idea on how to implement this in your code.
public class ObjectManager implements AutoCloseable {
private static class ObjectManagerFactory {
private static ObjectManager objMgr = new ObjectManager();
}
private ObjectManager() {}
public static ObjectManager getInstance() { return ObjectManagerFactory.objMgr; }
private static final int SIZE = 10;
private static BlockingQueue<AutoCloseable> objects = new LinkedBlockingQueue<AutoCloseable>();
private static ScheduledExecutorService sch;
static {
for(int cnt = 0 ; cnt < SIZE ; cnt++) {
objects.add(new AutoCloseable() {
#Override
public void close() throws Exception {
System.out.println(Thread.currentThread() + " - Adding object back to pool:" + this + " size: " + objects.size());
objects.put(this);
System.out.println(Thread.currentThread() + " - Added object back to pool:" + this);
}
});
}
sch = Executors.newSingleThreadScheduledExecutor();
sch.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
updateObjects();
}
}, 10, 10, TimeUnit.MICROSECONDS);
}
static void updateObjects() {
for(int cnt = 0 ; ! objects.isEmpty() && cnt < SIZE ; cnt++ ) {
try(AutoCloseable object = objects.take()) {
System.out.println(Thread.currentThread() + " - updateObjects - updated object: " + object + " size: " + objects.size());
} catch (Throwable t) {
// TODO Auto-generated catch block
t.printStackTrace();
}
}
}
public AutoCloseable getNext() {
try {
return objects.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
try (ObjectManager mgr = ObjectManager.getInstance()) {
for (int cnt = 0; cnt < 5; cnt++) {
try (AutoCloseable o = mgr.getNext()) {
System.out.println(Thread.currentThread() + " - Working with " + o);
Thread.sleep(1000);
} catch (Throwable t) {
t.printStackTrace();
}
}
} catch (Throwable tt) {
tt.printStackTrace();
}
}
#Override
public void close() throws Exception {
// TODO Auto-generated method stub
ObjectManager.sch.shutdownNow();
}
}
I will make some points here. In the getNextSocket method getOrderedDatacenters method will always return the same ordered list, so you will always pick from the same datacenters from start to end (it's not a problem).
How do you guarantee that two threads wont get the same liveSocket from getNextSocket?
What you are saying here it is true:
Concurrently, the timer thread may access the same 0MQ socket to ping
it.
I think the main problem here is that you don't distinguish between free sockets and reserved sockets.
One option as you said is to synchronize up on each socket. An other option is to keep a list of reserved sockets and when you want to get a next socket or to update sockets, to pick only from the free sockets. You don't want to update a socket which is already reserved.
Also you can take a look at here if it fits your needs.
There's a concept in operating systems software engineering called the critical section. A critical section occurs when 2 or more processes have shared data and they are concurrently executed, in this case, no process should modify or even read this shared data if there's another process accessing these data. So as a process enters the critical section it should notify all other concurrently executed processes that it's currently modifying the critical section, so all other processes should be blocked-waiting-to enter this critical section. you would ask who organize what process enters, this is another problem called process scheduling that controls what process should enter this critical section and the operating system do that for you.
so the best solution to you is using a semaphore where the value of the semaphore is the number of sockets, in your case, I think you have one socket so you will use a semaphore-Binary Semaphore- initialized with a semaphore value = 1, then your code should be divided into four main sections: critical section entry, the critical section, critical section exiting and remainder section.
Critical section entry: where a process enters the critical section and block all other processes. The semaphore will allow one Process-Thread-to enter the critical section-use a socket- and the value of the semaphore will be decremented-equal to zero-.
The critical section: the critical section code that the process should do.
Critical section exiting: the process releasing the critical section for another process to enter. The semaphore value will be incremented-equal to 1-allowing another process to enter
Remainder section: the rest of all your code excluding the previous 3 sections.
Now all you need is to open any Java tutorials about semaphores to know how to apply a semaphore in Java, it's really easy.
Mouhammed Elshaaer is right, but in additional you can also use any concurrent collection, for example ConcurrentHashMap where you can track that each thread works on different socket (for example ConcurrentHashMap key: socket hash code, value: thread hash code or smth else).
As for me it's a little bit stupid solution, but it can be used to.
For the problem of threads (Thread A and timer thread) accessing the same socket, I would keep 2 socket list for each datacenter:
list A: The sockets that are not in use
list B: The sockets that are in use
i.e.,
call synchronisation getNextSocket() to find an not-in-use socket from list A, remove it from list A and add it to list B;
call synchronisation returnSocket(Socket) upon receiving the reponse/ACK for a sent message (either business or ping), to move the socket from list B back to list A. Put a try {} finally {} block around "sending message" to make sure that the socket will be put back to list A even if there is an exception.
I have a simple solution maybe help you. I don't know if in Java you can add a custom attribute to each socket. In Socket.io you can. So I wanna considerate this (I will delete this answer if not).
You will add a boolean attribute called locked to each socket. So, when your thread check the first socket, locked attribute will be True. Any other thread, when ping THIS socket, will check if locked attribute is False. If not, getNextSocket.
So, in this stretch below...
...
for (SocketHolder liveSocket : liveSockets) {
Socket socket = liveSocket.getSocket();
...
You will check if socket is locked or not. If yes, kill this thread or interrupt this or go to next socket. (I don't know how you call it in Java).
So the process is...
Thread get an unlocked socket
Thread set this socket.locked to True.
Thread ping socket and do any stuff you want
Thread set this socket.locked to False.
Thread go to next.
Sorry my bad english :)
I have two local threadpools, one pool has 4 threads, second pool has 5 threads.
I want these two pools communicate with each other.
For example, first pool's second thread (1.2) communicates with the second pool`s fifth thread (2.5), i.e.
1.2 -> 2.5
1.1 -> 2.2
1.3 -> 2.1
1.4 -> 2.3
1.2 finished sending the message to 2.5 and wants to send the other message to the second pool, but 2.5 is still busy, but 2.4 if free to
process messages from 1.2
How do I make threads from first pool communicate to the first free thread from second pool?
How can I implement it in java?
Perhaps I should use a message brokers or something like that? (or BlockingQueue,Exchanger/Pipereader)
Thanks
(Your example is not clear, but I think you are asking for a scheme where the thread in one pool doesn't care which of the threads in the other pool gets the messages.)
There are probably many ways to do this, but a simple way is:
create a bounded message queue for each pool
each thread in each pool reads messages from its pool's queue
a thread in one pool sends a message to the other pool by adding the message to the other pool's queue.
A message broker could also work, but it is probably over-kill. You most likely don't want the reliability / persistence / distribution of a full-blown message broker.
How do I make threads from first pool communicate to the first free
thread from second pool?
I am not sure if you have any other specific needs but if both pools are local and you are simply willing to implement a typical producer - consumer pattern where N-Threads ( as part of a pool ) are acting as producer and another M-Threads ( as part of another pool ) are acting as consumer and you don't care which threads instance of second pool processes a message, I would go by a - BlockingQueue implementation.
You take an instance of BlockingQueue (like ArrayBlockingQueue OR LinkedBlockingQueue OR PriorityBlockingQueue and there are few more implementations in package java.util.concurrent) and share this instance among actual pool threads while restricting that - take() can be done by only consumer threads and by any consumer thread.
How can I implement it in java?
You create your pools like below ,
ExecutorService pool_1 = Executors.newFixedThreadPool(4);
ExecutorService pool_2 = Executors.newFixedThreadPool(4);
Then you give actual threads to these pools which are sharing a blocking queue. Threads can be created like below - its just a pseudo code.
public class Pool1Runnable implements Runnable {
private final BlockingQueue queue;
public Pool1Runnable(BlockingQueue queue){
this.queue=queue;
}
#Override
public void run() {
System.out.println("Pool1Runnable");
}
}
Now you write thread implementations for pool2 and make sure that their run() implementation uses take() on queue.
You create pool instances, thread instances - separate for producers and consumers (provide a single queue instance to all threads so it acts as a communication channel ) and then you execute these thread instances with pools.
Hope it helps !!
Most straightforward way as indicated by others is to have a BlockingQueue in between the pools. If I'm not mistaken your problem is same as having multiple producers and multiple consumers sending and processing messages respectively.
Here is one implementation which you can build on. There are few parameters for which comments have been added, you can tweak them based on your problem scenario. Basically, you have 2 pools and one more pool to invoke the producer and consumer in parallel.
public class MultiProducerConsumer {
private static final int MAX_PRODUCERS = 4;
private static final int MAX_CONSUMERS = 5;
private ExecutorService producerPool = new ThreadPoolExecutor(2, MAX_PRODUCERS, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
private ExecutorService consumerPool = new ThreadPoolExecutor(2, MAX_CONSUMERS, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
//ThreadPool for holding the main threads for consumer and producer
private ExecutorService mainPool = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
/**
* Indicates the stopping condition for the consumer, without this it has no idea when to stop
*/
private AtomicBoolean readerComplete = new AtomicBoolean(false);
/**
* This is the queue for passing message from producer to consumer.
* Keep queue size depending on how slow is your consumer relative to producer, or base it on resource constraints
*/
private BlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
MultiProducerConsumer multiProducerConsumer = new MultiProducerConsumer();
multiProducerConsumer.process();
System.out.println("Time taken in seconds - " + (System.currentTimeMillis() - startTime)/1000f);
}
private void process() throws InterruptedException {
mainPool.execute(this::consume);
mainPool.execute(this::produce);
Thread.sleep(10); // allow the pool to get initiated
mainPool.shutdown();
mainPool.awaitTermination(5, TimeUnit.SECONDS);
}
private void consume() {
try {
while (!readerComplete.get()) { //wait for reader to complete
consumeAndExecute();
}
while (!queue.isEmpty()) { //process any residue tasks
consumeAndExecute();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
consumerPool.shutdown();
consumerPool.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void consumeAndExecute() throws InterruptedException {
if (!queue.isEmpty()) {
String msg = queue.take(); //takes or waits if queue is empty
consumerPool.execute(() -> {
System.out.println("c-" + Thread.currentThread().getName() + "-" + msg);
});
}
}
private void produce() {
try {
for (int i = 0; i < MAX_PRODUCERS; i++) {
producerPool.execute(() -> {
try {
String random = getRandomNumber() + "";
queue.put(random);
System.out.println("p-" + Thread.currentThread().getName() + "-" + random);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
} finally {
try {
Thread.sleep(10); //allow pool to get initiated
producerPool.shutdown();
producerPool.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
readerComplete.set(true); //mark producer as done, so that consumer can exit
}
}
private int getRandomNumber() {
return (int) (Math.random() * 50 + 1);
}
}
Here is the output:
p-pool-1-thread-2-43
p-pool-1-thread-2-32
p-pool-1-thread-2-12
c-pool-2-thread-1-43
c-pool-2-thread-1-12
c-pool-2-thread-2-32
p-pool-1-thread-1-3
c-pool-2-thread-1-3
Time taken in seconds - 0.1
i want to introduce my problem first.
I have several WorkingThreads that are receiving a string, processing the string and afterwards sending the processed string to a global Queue like this:
class Main {
public static Queue<String> Q;
public static void main(String[] args) {
//start working threads
}
}
WorkingThread.java:
class WorkingThread extends Thread {
public void run() {
String input;
//do something with input
Main.q.append(processedString);
}
So now every 800ms another Thread called Inserter dequeues all the entries to formulate some sql, but thats not important.
class Inserter extends Thread {
public void run() {
while(!Main.Q.isEmpty()) {
System.out.print(".");
// dequeue and formulate some SQL
}
}
}
Everything works for about 5 to 10 minutes but then suddenly, i cannot see any dots printed (what is basically a heartbeat for the Inserter). The Queue is not empty i can assure that but the inserter just wont work even though it get started regulary.
I have a suspision that there is a problem when a worker wants to insert something while the Inserter dequeues the Queue, could this possibly be some kind of "deadlock"?
I really hope somebody has an explanation for this behaviour. I am looking forward to learn ;).
EDIT: I am using
Queue<String> Q = new LinkedList<String>();
You are not using a synchronized or thread safe Queue therefore you have a race hazard. Your use of a LinkedList shows a (slightly scary) lack of knowledge of this fact. You may want to read more about threading and thread safety before you try and tackle any more threaded code.
You must either synchronize manually or use one of the existing implementations provided by the JDK. Producer/consumer patterns are usually implemented using one of the BlockingQueue implementations.
A BlockingQueue of a bounded size will block producers trying to put if the queue is full. A BlockingQueue will always block consumers if the queue is empty.
This allows you to remove all of your custom logic that spins on the queue and waits for items.
A simple example using Java 8 lambdas would look like:
public static void main(String[] args) throws Exception {
final BlockingQueue<String> q = new LinkedBlockingQueue<>();
final ExecutorService executorService = Executors.newFixedThreadPool(4);
final Runnable consumer = () -> {
while (true) {
try {
System.out.println(q.take());
} catch (InterruptedException e) {
return;
}
}
};
executorService.submit(consumer);
final Stream<Runnable> producers = IntStream.range(0, 5).mapToObj(i -> () -> {
final Random random = ThreadLocalRandom.current();
while (true) {
q.add("Consumer " + i + " putting " + random.nextDouble());
try {
TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));
} catch (InterruptedException e) {
//ignore
}
}
});
producers.forEach(executorService::submit);
}
The consumer blocks on the BlockingQueue.take method and immediately there is an item available, it will be woken and will print the item. If there are no items, the thread will be suspended - allowing the physical CPU to do something else.
The producers each push a String onto the queue using add. As the queue is unbounded, add will always return true. In the case where there is likely to be a backlog of work the for consumer you can bound the queue and use the put method (that throws an InterruptedException so requires a try..catch which is why it's easier to use add) - this will automatically create flow control.
Seems more like synchronization issue.. You are trying to do a simulation of - Producer - Consumer problem. You need to synchronize your Queue or use a BlockingQueue. You probably have a race condition.
You are going to need to synchronize access to your Queue or
use ConcurrentLinkedQueue see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
or as also suggested using a BlockingQueue (depending on your requirements) http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html
For a more detailed explanation of the BlockingQueue see
http://tutorials.jenkov.com/java-util-concurrent/blockingqueue.html
The current project I am working on requires that I implement a way to efficiently pass a set of objects from one thread, that runs continuously, to the main thread. The current setup is something like the following.
I have a main thread which creates a new thread. This new thread operates continuously and calls a method based on a timer. This method fetches a group of messages from an online source and organizes them in a TreeSet.
This TreeSet then needs to be passed back to the main thread so that the messages it contains can be handled independent of the recurring timer.
For better reference my code looks like the following
// Called by the main thread on start.
void StartProcesses()
{
if(this.IsWindowing)
{
return;
}
this._windowTimer = Executors.newSingleThreadScheduledExecutor();
Runnable task = new Runnable() {
public void run() {
WindowCallback();
}
};
this.CancellationToken = false;
_windowTimer.scheduleAtFixedRate(task,
0, this.SQSWindow, TimeUnit.MILLISECONDS);
this.IsWindowing = true;
}
/////////////////////////////////////////////////////////////////////////////////
private void WindowCallback()
{
ArrayList<Message> messages = new ArrayList<Message>();
//TODO create Monitor
if((!CancellationToken))
{
try
{
//TODO fix epochWindowTime
long epochWindowTime = 0;
int numberOfMessages = 0;
Map<String, String> attributes;
// Setup the SQS client
AmazonSQS client = new AmazonSQSClient(new
ClasspathPropertiesFileCredentialsProvider());
client.setEndpoint(this.AWSSQSServiceUrl);
// get the NumberOfMessages to optimize how to
// Receive all of the messages from the queue
GetQueueAttributesRequest attributesRequest =
new GetQueueAttributesRequest();
attributesRequest.setQueueUrl(this.QueueUrl);
attributesRequest.withAttributeNames(
"ApproximateNumberOfMessages");
attributes = client.getQueueAttributes(attributesRequest).
getAttributes();
numberOfMessages = Integer.valueOf(attributes.get(
"ApproximateNumberOfMessages")).intValue();
// determine if we need to Receive messages from the Queue
if (numberOfMessages > 0)
{
if (numberOfMessages < 10)
{
// just do it inline it's less expensive than
//spinning threads
ReceiveTask(numberOfMessages);
}
else
{
//TODO Create a multithreading version for this
ReceiveTask(numberOfMessages);
}
}
if (!CancellationToken)
{
//TODO testing
_setLock.lock();
Iterator<Message> _setIter = _set.iterator();
//TODO
while(_setIter.hasNext())
{
Message temp = _setIter.next();
Long value = Long.valueOf(temp.getAttributes().
get("Timestamp"));
if(value.longValue() < epochWindowTime)
{
messages.add(temp);
_set.remove(temp);
}
}
_setLock.unlock();
// TODO deduplicate the messages
// TODO reorder the messages
// TODO raise new Event with the results
}
if ((!CancellationToken) && (messages.size() > 0))
{
if (messages.size() < 10)
{
Pair<Integer, Integer> range =
new Pair<Integer, Integer>(Integer.valueOf(0),
Integer.valueOf(messages.size()));
DeleteTask(messages, range);
}
else
{
//TODO Create a way to divide this work among
//several threads
Pair<Integer, Integer> range =
new Pair<Integer, Integer>(Integer.valueOf(0),
Integer.valueOf(messages.size()));
DeleteTask(messages, range);
}
}
}catch (AmazonServiceException ase){
ase.printStackTrace();
}catch (AmazonClientException ace) {
ace.printStackTrace();
}
}
}
As can be seen by some of the commenting, my current preferred way to handle this is by creating an event in the timer thread if there are messages. The main thread will then be listening for this event and handle it appropriately.
Presently I am unfamiliar with how Java handles events, or how to create/listen for them. I also do not know if it is possible to create events and have the information contained within them passed between threads.
Can someone please give me some advice/insight on whether or not my methods are possible? If so, where might I find some information on how to implement them as my current searching attempts are not proving fruitful.
If not, can I get some suggestions on how I would go about this, keeping in mind I would like to avoid having to manage sockets if at all possible.
EDIT 1:
The main thread will also be responsible for issuing commands based on the messages it receives, or issuing commands to get required information. For this reason the main thread cannot wait on receiving messages, and should handle them in an event based manner.
Producer-Consumer Pattern:
One thread(producer) continuosly stacks objects(messages) in a queue.
another thread(consumer) reads and removes objects from the queue.
If your problem fits to this, Try "BlockingQueue".
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html
It is easy and effective.
If the queue is empty, consumer will be "block"ed, which means the thread waits(so do not uses cpu time) until producer puts some objects. otherwise cosumer continuosly consumes objects.
And if the queue is full, prducer will be blocked until consumer consumes some objects to make a room in the queue, vice versa.
Here's a example:
(a queue should be same object in both producer and consumer)
(Producer thread)
Message message = createMessage();
queue.put(message);
(Consumer thread)
Message message = queue.take();
handleMessage(message);
I have a bunch of producer threads adding to a BlockingQueue and one worker thread taking objects. Now I want to extend this so two worker threads are taking objects, but doing different work on the objects. Here's the twist: I want an object that has been put on the queue to be worked on by both of the receiving threads.
If I keep using BlockingQueue, the two threads will compete for the objects, and only one of the worker threads will get the object.
So I'm looking for something similar to BlockingQueue, but with broadcast behaviour.
The application: The producer threads are actually creating performance measurements, and one of the workers is writing the measurements to a file, while the other worker is aggregating statistics.
I'm using Java 6.
So does such a mechanism exist? In Java SE? Elsewhere? Or do I need to code my own?
I'm looking for solutions with a small footprint - I'd prefer not to install some framework to do this.
One option: have three blocking queues. Your main producer puts items into a "broadcast" queue. You then have a consumer of that queue which consumes each item, putting it into both of the other queues, each of which is serviced by a single consumer:
Q2
---- Real Consumer 1
Q1 /
Producer ---- Broadcast Consumer
\
---- Real Consumer 2
Q3
Alternatively, you could give two blocking queues to the producer, and just get it to put the items it produces into both. That's less elegant, but slightly simpler overall :)
Jon Skeet idea is beautiful in its simplicity. Other than that you can use the disruptor pattern, which is faster and addresses exactly this problem. I can give you a code example with CoralQueue, which is an implementation of the disruptor pattern done by Coral Blocks, with which I am affiliated. It provides a data structure called Splitter that accepts a single producer offering messages and accepts multiple consumers polling messages, in a way that all messages are delivered to each and every consumer.
package com.coralblocks.coralqueue.sample.splitter;
import com.coralblocks.coralqueue.splitter.AtomicSplitter;
import com.coralblocks.coralqueue.splitter.Splitter;
import com.coralblocks.coralqueue.util.Builder;
public class Basics {
private static final int NUMBER_OF_CONSUMERS = 4;
public static void main(String[] args) {
Builder<StringBuilder> builder = new Builder<StringBuilder>() {
#Override
public StringBuilder newInstance() {
return new StringBuilder(1024);
}
};
final Splitter<StringBuilder> splitter = new AtomicSplitter<StringBuilder>(1024, builder, NUMBER_OF_CONSUMERS);
Thread producer = new Thread(new Runnable() {
private final StringBuilder getStringBuilder() {
StringBuilder sb;
while((sb = splitter.nextToDispatch()) == null) {
// splitter can be full if the size of the splitter
// is small and/or the consumer is too slow
// busy spin (you can also use a wait strategy instead)
}
return sb;
}
#Override
public void run() {
StringBuilder sb;
while(true) { // the main loop of the thread
// (...) do whatever you have to do here...
// and whenever you want to send a message to
// the other thread you can just do:
sb = getStringBuilder();
sb.setLength(0);
sb.append("Hello!");
splitter.flush();
// you can also send in batches to increase throughput:
sb = getStringBuilder();
sb.setLength(0);
sb.append("Hi!");
sb = getStringBuilder();
sb.setLength(0);
sb.append("Hi again!");
splitter.flush(); // dispatch the two messages above...
}
}
}, "Producer");
final Thread[] consumers = new Thread[NUMBER_OF_CONSUMERS];
for(int i = 0; i < consumers.length; i++) {
final int index = i;
consumers[i] = new Thread(new Runnable() {
#SuppressWarnings("unused")
#Override
public void run() {
while (true) { // the main loop of the thread
// (...) do whatever you have to do here...
// and whenever you want to check if the producer
// has sent a message you just do:
long avail;
while((avail = splitter.availableToPoll(index)) == 0) {
// splitter can be empty!
// busy spin (you can also use a wait strategy instead)
}
for(int i = 0; i < avail; i++) {
StringBuilder sb = splitter.poll(index);
// (...) do whatever you want to do with the data
// just don't call toString() to create garbage...
// copy byte-by-byte instead...
}
splitter.donePolling(index);
}
}
}, "Consumer" + index);
}
for(int i = 0; i < consumers.length; i++) {
consumers[i].start();
}
producer.start();
}
}
Disclaimer: I am one of the developers of CoralQueue.