So I have to create three Teller threads, and 100 Client threads.
Each thread must follow a sequence of actions, printing a record of each action.
the Teller threads must: notify the client that its available, accept id and transaction from a client, respond to client, .. and so on
the client has a similar set of actions: wait in line, when signaled select a free teller, etc
What I don't understand is, how do I get these threads to communicate?
So I make three Teller threads from the main method, 100 client threads, how exactly do I connect a client thread to a teller thread? Obviously when the three teller threads open, they can only take 3 clients, so 97 other client threads will be waiting. How do I stop the Client's run() method so the threads are still alive while waiting for an open Teller?
You can use a Count Down Latch.
Basically it works like this:
Count down latch signal helps by making client wait if all tellers are busy at the moment and notifies client thread if signal's count reaches 0 ( which means it's my turn).
My suggestion is, create a count down latch signal with count equal to 1 for each client and store them in a data structure(I recommend a queue), so everytime a teller is done with a client just pop a count down latch signal from the queue, then decrease popped signal's count to 0, so the client with this signal gets notified.
I recommend a queue because after every pop it deletes the element, so there are no any data races ( thread's reading the same element at the same time, which makes a client be served by two threads ).
I hope this helps.
Exchanging data between classes is done via class methods.
Likewise, exchanging messages between Threads is done via class methods.
If everything is local, ie you don't have to send anything over an online network, then you can try the following code:
import java.util.LinkedList;
import java.util.Objects;
import java.util.Queue;
import java.util.Random;
public class Main {
public static class MessageSource {
}
public static class Message<S extends MessageSource> {
private final S origin;
public Message(final S origin) {
this.origin = Objects.requireNonNull(origin);
}
public S getOrigin() {
return origin;
}
}
public static class ClientRequest extends Message<Client> {
public ClientRequest(final Client origin) {
super(origin);
}
}
public static class TellerResponse extends Message<Teller> {
public TellerResponse(final Teller origin) {
super(origin);
}
}
public static class Teller extends MessageSource implements Runnable {
private final Queue<ClientRequest> sharedQueue;
public Teller(final Queue<ClientRequest> sharedQueue) {
this.sharedQueue = Objects.requireNonNull(sharedQueue);
}
#Override
public void run() {
try {
final Random rand = new Random();
while (true) {
final ClientRequest r;
synchronized (sharedQueue) {
while (sharedQueue.isEmpty()) {
System.out.println("Teller " + hashCode() + " says queue is empty.");
sharedQueue.wait();
}
r = sharedQueue.poll();
}
System.out.println("Teller " + hashCode() + " currently seving request from Client " + r.getOrigin().hashCode() + "...");
Thread.sleep(250 + rand.nextInt(250)); //Delay a bit, to simulate serving the request and creating the response...
r.getOrigin().response(new TellerResponse(this)); //One could say that this simulates an RPC call :P
}
}
catch (final InterruptedException ix) {
System.err.println("Teller " + hashCode() + " stopped serving clients abruptly: " + ix);
}
}
}
public static class Client extends MessageSource implements Runnable {
private final Queue<ClientRequest> sharedQueue;
private TellerResponse privateQueue; //Since responses will be received here, I call this a queue (although it's not, because we know we can serve only one response at a time).
public Client(final Queue<ClientRequest> sharedQueue) {
this.sharedQueue = Objects.requireNonNull(sharedQueue);
}
public synchronized void response(final TellerResponse r) {
privateQueue = r;
notifyAll(); //Could be notify(). No difference would it make in this specific case.
}
#Override
public void run() {
//I'm just implementing random count of random-data requests...
final Random rand = new Random();
final int numberOfRequests = 5 + rand.nextInt(6);
try {
for (int i = 0; i < numberOfRequests; ++i) {
final ClientRequest req = new ClientRequest(this);
synchronized (sharedQueue) {
sharedQueue.add(req);
sharedQueue.notifyAll(); //Could be notify(). No difference would it make in this specific case.
}
synchronized (this) {
while (privateQueue == null)
wait();
System.out.println("Client " + hashCode() + " can consume the " + privateQueue.getOrigin().hashCode() + " Teller's response...");
privateQueue = null;
}
}
}
catch (final InterruptedException ix) {
System.err.println("Client " + hashCode() + " stopped receiving responses abruptly: " + ix);
}
}
}
public static void main(final String[] args) {
final Queue<ClientRequest> requests = new LinkedList<>();
for (int i = 0; i < 100; ++i)
new Thread(new Client(requests)).start();
for (int i = 0; i < 3; ++i)
new Thread(new Teller(requests)).start();
}
}
A single ClientRequest is answered by a Teller with a single TellerResponse.
Now you have to extend the classes ClientRequest and TellerResponse according to your needs (ie implement what data should be exchanged).
This implementation is a producer-consumer pattern where both the Tellers and the Clients are both producers and consumers.
This implementation uses a shared queue to exchange messages from clients to tellers.
There is no stopping condition for the tellers (which makes them wait indefinetly at the end of the clients' requests) which will make the program wait forever at the end of the clients' requests.
But this is expected since we have no terminating condition.
The clients will run creating from 5 up to 10 requests. The tellers will delay each response from 250 to 500ms. With 3 tellers and 100 clients, that makes us about from 42 up to 167 seconds runtime.
A more reallistic communication approach I guess would use PipedInputStreams and PipedOutputStreams to simulate traffic over blocking streams (such as network traffic).
Related
I have two classes that extends Thread. Class One, and class Two.
In my driver class, I create three threads of class One, and one hundred threads of class Two.
Each class One thread needs to notify every class Two thread that it's available to interact. After the two threads interact, the thread One moves on to another class Two thread that hasn't had an interaction with a class One thread.
How do I connect the two types of threads? How do I connect class 1 and class 2 threads. How does a thread using class 1 let every thread using class 2 know that it is available for interaction?
ex code:
public class Driver {
public static Semaphore sem = new Semaphore(1);
public static void main(String[] args) {
// TODO Auto-generated method stub
Teller tellerOne = new Teller(1);
Teller tellerTwo = new Teller(2);
Teller tellerThree = new Teller(3);
tellerOne.start();
tellerTwo.start();
tellerThree.start();
Client[] clients = new Client[10];
for(int i = 0; i<10; i++){
clients[i] = new Client(i);
clients[i].start();
}
System.out.println("Bank closes");
//end main method. do not write past this line
}
public class Teller extends Thread {
public int id;
public boolean bankOpen;
public Semaphore tsem;
Teller(int id){
this.id = id;
}
public void run(){
System.out.println("Teller " + id + " is available");
//end of run
}
//method to notify availability to client
public void notifyAvailabilityToClient(){
}
//end teller class, do not write past this line
public class Client extends Thread {
public int id;
public String status;
public Semaphore csem;
Client(int id){
this.id = id;
}
public void run(){
Random rand = new Random();
int withdrawOrDeposit = rand.nextInt(100);
withdrawOrDeposit = withdrawOrDeposit%2;
//if wORd%2 = 0, withdraw, else deposit
if(withdrawOrDeposit==0){
status="Withdraw";
}
else{
status="Deposit";
}
System.out.println("Client " + id + " waits in line to make a " + status);
//end of run method, do not write past this
}
//method to select an open Teller
public void selectAvailableTeller(){
}
//end of client class, do not write past this line
Btw I can use classes: Semaphore and Threads
I would not normally write code in which different threads meet up with each other, but since this appears to be a homework assignment...
In my solution there would be a single, blocking queue. When a "teller" thread starts up, and each time it finishes "interacting" with a customer, it would put its self into the queue, and then wait for a new customer to start an interaction. The customers all would wait to take() a teller from the queue, and when they get one,... "interact" with it.
If it was not homework I would do something entirely different. I don't know why "customer" threads are a thing, but I don't see any use for "teller" threads at all. There might be some kind of limited-availability Teller objects, but they would not be threads. The customer threads could "interact" by simply calling Teller methods or, if necessary, by submitting tasks that call Teller methods to a generic thread pool.
We are creating a rest application. And we have an edge condition where parallel actions are not supported on same object.
For example :
Not supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object A
Request 3 for action ABC for object A
Supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object B
Request 3 for action ABC for object C
Now, the object count is not fixed. we can have n number of such objects.
I want that if a request for object A is under progress then other request for object A should wait for existing task on object A to get over.
But I am not able to figure out the algorithm for this purpose.
I could plan for below design but not able to figure out on how to use the locking since all objects can be different.
A queue which stores the entry for object A when request comes.
Entry gets deleted if response is sent
If an entry is already present, then wait for existing request to get over.
If entry not present, then execute immediately.
Now task on object A should not impact the task on object B. So they must accept unique locks.
And also, request cannot go standalone and be queued. Somehow I have to make the current thread sleep so that I can send response to user.
Can anyone guide here?
UPDATED based on comments from my original response
The ideal model for something like that would be using an actor system such as Akka.
But your comment states that this will happen in the context on a REST application where threads will be blocked already by request processing.
In this case, the idea would be using a per-object-guard such as:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
public class ObjectGuard<K> {
private final ConcurrentMap<K, CountDownLatch> activeTasks = new ConcurrentHashMap<>();
public Guard guardFor(final K key) throws InterruptedException {
if (key == null) {
throw new NullPointerException("key cannot be null");
}
final CountDownLatch latch = new CountDownLatch(1);
while (true) {
final CountDownLatch currentOwner = activeTasks.putIfAbsent(key, latch);
if (currentOwner == null) {
break;
} else {
currentOwner.await();
}
}
return () -> {
activeTasks.remove(key);
latch.countDown();
};
}
public interface Guard extends AutoCloseable {
#Override
void close();
}
}
You would use it as follows:
class RequestProcessor {
private final ObjectGuard<String> perObjectGuard = new ObjectGuard<>();
public String process(String objectId, String op) throws InterruptedException {
// Only one thread per object id can be present at any given time
try (ObjectGuard.Guard ignore = perObjectGuard.guardFor(objectId)) {
String result = ... // compute response
}
}
}
If two concurrent calls to process are received for the same object id, only one will be processed, the others wait their turn to process a request on that object.
An object which executes requests serially is known as Actor. The most widely known java actor library is named Akka. The most simple (one page) actor implementation is my SimpleActor.java.
Signalling like juancn does in his answer is not my strong suit, so I made an even cruder solution using one Semaphore for signalling combined with a request-counter.
There is one lock involved (subjectsLock) which synchronizes everything at one point in time. The lock is required to ensure there are no memory leaks: since there can be any number of subjects (a.k.a. object identifiers in your question), cleanup is essential. And cleanup requires knowing when something can be removed and that is difficult to determine without a lock that brings everything to one known state at a certain point in time.
The test in the main-method in the code shown below is a bit hard to read, but it serves as a starting point for a demonstration of how the code works internally. The main logic is in the methods executeRequest, addSubject and removeSubject. If those three methods do not make sense, another solution should be used.
Stress-testing will have to determine if this solution is fast enough: it depends on the number of requests (per second) and the amount of time it takes to complete an action. If there are many requests and the action is short/fast, the (synchronization) overhead from the lock could be to high.
// package so;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
public class RequestQueue {
public static void main(String[] args) {
// Randomized test for "executeRequest" method below.
final int threadCount = 4;
ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
try {
final int requestCount = 100;
final RequestQueue rq = new RequestQueue();
final Random random = new Random();
IntStream.range(0, requestCount).forEach(i -> threadPool.execute(new Runnable() {
#Override
public void run() {
try {
String subject = "" + (char) (((int)'A') + random.nextInt(threadCount));
rq.executeRequest(subject, new SleepAction(i, subject, 50 + random.nextInt(5)));
} catch (Exception e) {
e.printStackTrace();
}
}
}));
sleep(100); // give threads a chance to start executing.
while (true) {
sleep(200);
List<String> subjects = rq.getSubjects();
System.out.println("Subjects: " + subjects);
if (subjects.isEmpty()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
private Map<String, QueueLock> subjects = new LinkedHashMap<>();
// a fair ReentrantLock is a little bit slower but ensures everybody gets their turn in orderly fashion.
private final ReentrantLock subjectsLock = new ReentrantLock(true);
private class QueueLock {
// a fair Semaphore ensures all requests are executed in the order they arrived.
final Semaphore turn = new Semaphore(1, true);
final AtomicInteger requests = new AtomicInteger(1);
public String toString() { return "request: " + requests.get(); }
}
/**
* Allow all requests for different subjects to execute in parallel,
* execute actions for the same subject one after another.
* Calling thread runs the action (possibly after waiting a bit when an action for a subject is already in progress).
*/
public String executeRequest(String subject, Runnable action) throws InterruptedException {
QueueLock qlock = addSubject(subject);
try {
int requestsForSubject = qlock.requests.get();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " waiting for turn " + requestsForSubject);
}
qlock.turn.acquire();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " taking turn " + qlock.requests.get());
}
action.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
removeSubject(subject);
}
return timeSinceStart() + " " + subject;
}
private QueueLock addSubject(String s) {
QueueLock qlock = null;
subjectsLock.lock();
try {
qlock = subjects.get(s);
if (qlock == null) {
qlock = new QueueLock();
subjects.put(s, qlock);
} else {
qlock.requests.incrementAndGet();
}
} finally {
subjectsLock.unlock();
}
return qlock;
}
private boolean removeSubject(String s) {
boolean removed = false;
subjectsLock.lock();
try {
QueueLock qlock = subjects.get(s);
if (qlock.requests.decrementAndGet() == 0) {
subjects.remove(s);
removed = true;
} else {
qlock.turn.release();
}
} finally {
subjectsLock.unlock();
}
return removed;
}
public List<String> getSubjects() {
List<String> subjectsBeingProcessed = new ArrayList<>();
subjectsLock.lock();
try {
// maintains insertion order, see https://stackoverflow.com/a/18929873/3080094
subjectsBeingProcessed.addAll(subjects.keySet());
} finally {
subjectsLock.unlock();
}
return subjectsBeingProcessed;
}
public static class SleepAction implements Runnable {
final int requestNumber;
final long sleepTime;
final String subject;
public SleepAction(int requestNumber, String subject, long sleepTime) {
this.requestNumber = requestNumber;
this.sleepTime = sleepTime;
this.subject = subject;
}
#Override
public void run() {
System.out.println(toString() + " sleeping for " + sleepTime);
sleep(sleepTime);
System.out.println(toString() + " done");
}
public String toString() {return timeSinceStart() + " " + subject + " [" + Thread.currentThread().getName() + "] " + String.format("%03d",requestNumber); }
}
public static final long START_TIME = System.currentTimeMillis();
public static String timeSinceStart() {
return String.format("%05d", (System.currentTimeMillis() - START_TIME));
}
public static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
I have one producer and many consumers.
the producer is fast and generating a lot of results
tokens with the same value need to be processed sequentially
tokens with different values must be processed in parallel
creating new Runnables would be very expensive and also the production code could work with 100k of Tokens(in order to create a Runnable I have to pass to the constructor some complex to build objects)
Can I achieve the same results with a simpler algorithm? Nesting a syncronization block with a reentrant lock seems a bit unnatural.
Are there any race conditions you might notice?
Update: a second solution I found was working with 3 collections. One to cache the producer results, second a blocking queue and 3rd using a list to track in the tasks in progress. Again a bit to complicated.
My version of code
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
public class Main1 {
static class Token {
private int order;
private String value;
Token() {
}
Token(int o, String v) {
order = o;
value = v;
}
int getOrder() {
return order;
}
String getValue() {
return value;
}
}
private final static BlockingQueue<Token> queue = new ArrayBlockingQueue<Token>(10);
private final static ConcurrentMap<String, Object> locks = new ConcurrentHashMap<String, Object>();
private final static ReentrantLock reentrantLock = new ReentrantLock();
private final static Token STOP_TOKEN = new Token();
private final static List<String> lockList = Collections.synchronizedList(new ArrayList<String>());
public static void main(String[] args) {
ExecutorService producerExecutor = Executors.newSingleThreadExecutor();
producerExecutor.submit(new Runnable() {
public void run() {
Random random = new Random();
try {
for (int i = 1; i <= 100; i++) {
Token token = new Token(i, String.valueOf(random.nextInt(1)));
queue.put(token);
}
queue.put(STOP_TOKEN);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
ExecutorService consumerExecutor = Executors.newFixedThreadPool(10);
for(int i=1; i<=10;i++) {
// creating to many runnable would be inefficient because of this complex not thread safe object
final Object dependecy = new Object(); //new ComplexDependecy()
consumerExecutor.submit(new Runnable() {
public void run() {
while(true) {
try {
//not in order
Token token = queue.take();
if (token == STOP_TOKEN) {
queue.add(STOP_TOKEN);
return;
}
System.out.println("Task start" + Thread.currentThread().getId() + " order " + token.getOrder());
Random random = new Random();
Thread.sleep(random.nextInt(200)); //doLongRunningTask(dependecy)
lockList.remove(token.getValue());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}});
}
}}
You can pre-create set of Runnables which will pick incoming tasks (tokens) and place them in queues according to their order value.
As pointed out in comments, it's not guaranteed that tokens with different values will always execute in parallel (all in all, you are bounded, at least, by nr of physical cores in your box). However, it is guaranteed that tokens with same order will be executed in the order of arrival.
Sample code:
/**
* Executor which ensures incoming tasks are executed in queues according to provided key (see {#link Task#getOrder()}).
*/
public class TasksOrderingExecutor {
public interface Task extends Runnable {
/**
* #return ordering value which will be used to sequence tasks with the same value.<br>
* Tasks with different ordering values <i>may</i> be executed in parallel, but not guaranteed to.
*/
String getOrder();
}
private static class Worker implements Runnable {
private final LinkedBlockingQueue<Task> tasks = new LinkedBlockingQueue<>();
private volatile boolean stopped;
void schedule(Task task) {
tasks.add(task);
}
void stop() {
stopped = true;
}
#Override
public void run() {
while (!stopped) {
try {
Task task = tasks.take();
task.run();
} catch (InterruptedException ie) {
// perhaps, handle somehow
}
}
}
}
private final Worker[] workers;
private final ExecutorService executorService;
/**
* #param queuesNr nr of concurrent task queues
*/
public TasksOrderingExecutor(int queuesNr) {
Preconditions.checkArgument(queuesNr >= 1, "queuesNr >= 1");
executorService = new ThreadPoolExecutor(queuesNr, queuesNr, 0, TimeUnit.SECONDS, new SynchronousQueue<>());
workers = new Worker[queuesNr];
for (int i = 0; i < queuesNr; i++) {
Worker worker = new Worker();
executorService.submit(worker);
workers[i] = worker;
}
}
public void submit(Task task) {
Worker worker = getWorker(task);
worker.schedule(task);
}
public void stop() {
for (Worker w : workers) w.stop();
executorService.shutdown();
}
private Worker getWorker(Task task) {
return workers[task.getOrder().hashCode() % workers.length];
}
}
By the nature of your code, the only way to guarantee that the tokens with the
same value are processed in serial manner is to wait for STOP_TOKEN to arrive.
You'll need single producer-single consumer setup, with consumer collecting and sorting
the tokens by their value (into the Multimap, let say).
Only then you know which tokens can be process serially and which may be processed in parallel.
Anyway, I advise you to look at LMAX Disruptor, which offers very effective way for sharing data between threads.
It doesn't suffer from synchronization overhead as Executors as it is lock free (which may give you nice performance benefits, depending on the way how you process the data).
The solution using two Disruptors
// single thread for processing as there will be only on consumer
Disruptor<InEvent> inboundDisruptor = new Disruptor<>(InEvent::new, 32, Executors.newSingleThreadExecutor());
// outbound disruptor that uses 3 threads for event processing
Disruptor<OutEvent> outboundDisruptor = new Disruptor<>(OutEvent::new, 32, Executors.newFixedThreadPool(3));
inboundDisruptor.handleEventsWith(new InEventHandler(outboundDisruptor));
// setup 3 event handlers, doing round robin consuming, effectively processing OutEvents in 3 threads
outboundDisruptor.handleEventsWith(new OutEventHandler(0, 3, new Object()));
outboundDisruptor.handleEventsWith(new OutEventHandler(1, 3, new Object()));
outboundDisruptor.handleEventsWith(new OutEventHandler(2, 3, new Object()));
inboundDisruptor.start();
outboundDisruptor.start();
// publisher code
for (int i = 0; i < 10; i++) {
inboundDisruptor.publishEvent(InEventTranslator.INSTANCE, new Token());
}
The event handler on the inbound disruptor just collects incoming tokens. When STOP token is received, it publishes the series of tokens to outbound disruptor for further processing:
public class InEventHandler implements EventHandler<InEvent> {
private ListMultimap<String, Token> tokensByValue = ArrayListMultimap.create();
private Disruptor<OutEvent> outboundDisruptor;
public InEventHandler(Disruptor<OutEvent> outboundDisruptor) {
this.outboundDisruptor = outboundDisruptor;
}
#Override
public void onEvent(InEvent event, long sequence, boolean endOfBatch) throws Exception {
if (event.token == STOP_TOKEN) {
// publish indexed tokens to outbound disruptor for parallel processing
tokensByValue.asMap().entrySet().stream().forEach(entry -> outboundDisruptor.publishEvent(OutEventTranslator.INSTANCE, entry.getValue()));
} else {
tokensByValue.put(event.token.value, event.token);
}
}
}
Outbound event handler processes tokens of the same value sequentially:
public class OutEventHandler implements EventHandler<OutEvent> {
private final long order;
private final long allHandlersCount;
private Object yourComplexDependency;
public OutEventHandler(long order, long allHandlersCount, Object yourComplexDependency) {
this.order = order;
this.allHandlersCount = allHandlersCount;
this.yourComplexDependency = yourComplexDependency;
}
#Override
public void onEvent(OutEvent event, long sequence, boolean endOfBatch) throws Exception {
if (sequence % allHandlersCount != order ) {
// round robin, do not consume every event to allow parallel processing
return;
}
for (Token token : event.tokensToProcessSerially) {
// do procesing of the token using your complex class
}
}
}
The rest of the required infrastructure (purpose described in the Disruptor docs):
public class InEventTranslator implements EventTranslatorOneArg<InEvent, Token> {
public static final InEventTranslator INSTANCE = new InEventTranslator();
#Override
public void translateTo(InEvent event, long sequence, Token arg0) {
event.token = arg0;
}
}
public class OutEventTranslator implements EventTranslatorOneArg<OutEvent, Collection<Token>> {
public static final OutEventTranslator INSTANCE = new OutEventTranslator();
#Override
public void translateTo(OutEvent event, long sequence, Collection<Token> tokens) {
event.tokensToProcessSerially = tokens;
}
}
public class InEvent {
// Note that no synchronization is used here,
// even though the field is used among multiple threads.
// Memory barrier used by Disruptor guarantee changes are visible.
public Token token;
}
public class OutEvent {
// ... again, no locks.
public Collection<Token> tokensToProcessSerially;
}
public class Token {
String value;
}
If you have lots of different tokens, then the simplest solution is to create some number of single-thread executors (about 2x your number of cores), and then distribute each task to an executor determined by the hash of its token.
That way all tasks with the same token will go to the same executor and execute sequentially, because each executor only has one thread.
If you have some unstated requirements about scheduling fairness, then it is easy enough to avoid any significant imbalances by having the producer thread queue up its requests (or block) before distributing them, until there are, say, less than 10 requests per executor outstanding.
The following solution will only use a single Map that is used by the producer and consumers to process orders in sequential order for each order number while processing different order numbers in parallel. Here is the code:
public class Main {
private static final int NUMBER_OF_CONSUMER_THREADS = 10;
private static volatile int sync = 0;
public static void main(String[] args) {
final ConcurrentHashMap<String,Controller> queues = new ConcurrentHashMap<String, Controller>();
final CountDownLatch latch = new CountDownLatch(NUMBER_OF_CONSUMER_THREADS);
final AtomicBoolean done = new AtomicBoolean(false);
// Create a Producer
new Thread() {
{
this.setDaemon(true);
this.setName("Producer");
this.start();
}
public void run() {
Random rand = new Random();
for(int i =0 ; i < 1000 ; i++) {
int order = rand.nextInt(20);
String key = String.valueOf(order);
String value = String.valueOf(rand.nextInt());
Controller controller = queues.get(key);
if (controller == null) {
controller = new Controller();
queues.put(key, controller);
}
controller.add(new Token(order, value));
Main.sync++;
}
done.set(true);
}
};
while (queues.size() < 10) {
try {
// Allow the producer to generate several entries that need to
// be processed.
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
// System.out.println(queues);
// Create the Consumers
ExecutorService consumers = Executors.newFixedThreadPool(NUMBER_OF_CONSUMER_THREADS);
for(int i = 0 ; i < NUMBER_OF_CONSUMER_THREADS ; i++) {
consumers.submit(new Runnable() {
private Random rand = new Random();
public void run() {
String name = Thread.currentThread().getName();
try {
boolean one_last_time = false;
while (true) {
for (Map.Entry<String, Controller> entry : queues.entrySet()) {
Controller controller = entry.getValue();
if (controller.lock(this)) {
ConcurrentLinkedQueue<Token> list = controller.getList();
Token token;
while ((token = list.poll()) != null) {
try {
System.out.println(name + " processing order: " + token.getOrder()
+ " value: " + token.getValue());
Thread.sleep(rand.nextInt(200));
} catch (InterruptedException e) {
}
}
int last = Main.sync;
queues.remove(entry.getKey());
while(done.get() == false && last == Main.sync) {
// yield until the producer has added at least another entry
Thread.yield();
}
// Purge any new entries added
while ((token = list.poll()) != null) {
try {
System.out.println(name + " processing order: " + token.getOrder()
+ " value: " + token.getValue());
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
controller.unlock(this);
}
}
if (one_last_time) {
return;
}
if (done.get()) {
one_last_time = true;
}
}
} finally {
latch.countDown();
}
}
});
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
consumers.shutdown();
System.out.println("Exiting.. remaining number of entries: " + queues.size());
}
}
Note that the Main class contains a queues instance that is a Map. The map key is the order id that you want to process sequentially by the consumers. The value is a Controller class that will contain all of the orders associated with that order id.
The producer will generate the orders and add the order, (Token), to its associated Controller. The consumers will iterator over the queues map values and call the Controller lock method to determine if it can process orders for that particular order id. If the lock returns false it will check the next Controller instance. If the lock returns true, it will process all orders and then check the next Controller.
updated Added the sync integer that is used to guarantee that when an instance of the Controller is removed from the queues map. All of its entries will be consumed. There was an logic error in the consumer code where the unlock method was called to soon.
The Token class is similar to the one that you've posted here.
class Token {
private int order;
private String value;
Token(int order, String value) {
this.order = order;
this.value = value;
}
int getOrder() {
return order;
}
String getValue() {
return value;
}
#Override
public String toString() {
return "Token [order=" + order + ", value=" + value + "]\n";
}
}
The Controller class that follows is used to insure that only a single thread within the thread pool will be processing the orders. The lock/unlock methods are used to determine which of the threads will be allowed to process the orders.
class Controller {
private ConcurrentLinkedQueue<Token> tokens = new ConcurrentLinkedQueue<Token>();
private ReentrantLock lock = new ReentrantLock();
private Runnable current = null;
void add(Token token) {
tokens.add(token);
}
public ConcurrentLinkedQueue<Token> getList() {
return tokens;
}
public void unlock(Runnable runnable) {
lock.lock();
try {
if (current == runnable) {
current = null;
}
} finally {
lock.unlock();
}
}
public boolean lock(Runnable runnable) {
lock.lock();
try {
if (current == null) {
current = runnable;
}
} finally {
lock.unlock();
}
return current == runnable;
}
#Override
public String toString() {
return "Controller [tokens=" + tokens + "]";
}
}
Additional information about the implementation. It uses a CountDownLatch to insure that all produced orders will be processed prior to the process exiting. The done variable is just like your STOP_TOKEN variable.
The implementation does contain an issue that you would need to resolve. There is the issue that it does not purge the controller for an order id when all of the orders have been processed. This will cause instances where a thread in the thread pool gets assigned to a controller that contains no orders. Which will waste cpu cycles that could be used to perform other tasks.
Is all you need is to ensure that tokens with the same value are not being processed concurrently? Your code is too messy to understand what you mean (it does not compile, and has lots of unused variables, locks and maps, that are created but never used). It looks like you are greatly overthinking this. All you need is one queue, and one map.
Something like this I imagine:
class Consumer implements Runnable {
ConcurrentHashMap<String, Token> inProcess;
BlockingQueue<Token> queue;
public void run() {
Token token = null;
while ((token = queue.take()) != null) {
if(inProcess.putIfAbsent(token.getValue(), token) != null) {
queue.put(token);
continue;
}
processToken(token);
inProcess.remove(token.getValue());
}
}
}
tokens with the same value need to be processed sequentially
The way to insure that any two things happen in sequence is to do them in the same thread.
I'd have a collection of however many worker threads, and I'd have a Map. Any time I get a token that I've not seen before, I'll pick a thread at random, and enter the token and the thread into the map. From then on, I'll use that same thread to execute tasks associated with that token.
creating new Runnables would be very expensive
Runnable is an interface. Creating new objects that implement Runnable is not going to be significantly more expensive than creating any other kind of object.
Maybe I'm misunderstanding something. But it seems that it would be easier to filter the Tokens with same value from the ones with different values into two different queues initially.
And then use Stream with either map or foreach for the sequential. And simply use the parallel stream version for the rest.
If your Tokens in production environment are lazily generated and you only get one at a time you simply make some sort of filter which distributes them to the two different queues.
If you can implement it with Streams I suqqest doing that as they are simple, easy to use and FAST!
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
I made a brief example of what I mean. In this case the numbers Tokens are sort of artificially constructed but thats beside the point. Also the streams are both initiated on the main thread which would probably also not be ideal.
public static void main(String args[]) {
ArrayList<Token> sameValues = new ArrayList<Token>();
ArrayList<Token> distinctValues = new ArrayList<Token>();
Random random = new Random();
for (int i = 0; i < 100; i++) {
int next = random.nextInt(100);
Token n = new Token(i, String.valueOf(next));
if (next == i) {
sameValues.add(n);
} else {
distinctValues.add(n);
}
}
distinctValues.stream().parallel().forEach(token -> System.out.println("Distinct: " + token.value));
sameValues.stream().forEach(token -> System.out.println("Same: " + token.value));
}
I am not entirely sure I have understood the question but I'll take a stab at an algorithm.
The actors are:
A queue of tasks
A pool of free executors
A set of in-process tokens currently being processed
A controller
Then,
Initially all executors are available and the set is empty
controller picks an available executor and goes through the queue looking for a task with a token that is not in the in-process set and when it finds it
adds the token to the in-process set
assigns the executor to process the task and
goes back to the beginning of the queue
the executor removes the token from the set when it is done processing and adds itself back to the pool
One way of doing this is having one executor for sequence processing and one for parallel processing. We also need a single threaded manager service that will decide to which service token needs to be submitted for processing.
// Queue to be shared by both the threads. Contains the tokens produced by producer.
BlockingQueue tokenList = new ArrayBlockingQueue(10);
private void startProcess() {
ExecutorService producer = Executors.newSingleThreadExecutor();
final ExecutorService consumerForSequence = Executors
.newSingleThreadExecutor();
final ExecutorService consumerForParallel = Executors.newFixedThreadPool(10);
ExecutorService manager = Executors.newSingleThreadExecutor();
producer.submit(new Producer(tokenList));
manager.submit(new Runnable() {
public void run() {
try {
while (true) {
Token t = tokenList.take();
System.out.println("consumed- " + t.orderid
+ " element");
if (t.orderid % 7 == 0) { // any condition to check for sequence processing
consumerForSequence.submit(new ConsumerForSequenceProcess(t));
} else {
ConsumerForParallel.submit(new ConsumerForParallelProcess(t));
}
}
}
catch (InterruptedException e) { // TODO Auto-generated catch
// block
e.printStackTrace();
}
}
});
}
I think there is a more fundamental design issue hidden behind this task, but ok. I cant figure out from you problem description if you want in-order execution or if you just want operations on tasks described by single tokens to be atomic/transactional. What i propose below feels more like a "quick fix" to this issue than a real solution.
For the real "ordered execution" case I propose a solution which is based on queue proxies which order the output:
Define a implementation of Queue which provides a factory method generating proxy queues which are represented to the producer side by a this single queue object; the factory method should also register these proxy queue objects. adding an element to the input queue should add it directly to one of the output queues if it matches one of the elements in one of the output queues. Otherwise add it to any (the shortest) output queue. (implement the check for this efficiently). Alternatively (slightly better): don't do this when the element is added, but when any of the output queues runs empty.
Give each of your runnable consumers an field storing an individual Queue interface (instead of accessing a single object). Initialize this field by a the factory method defined above.
For the transaction case i think it's easier to span more threads than you have cores (use statistics to calculate this), and implement the blocking mechanism on an lower (object) level.
I have an app with two threads, 1 that writes to a queue and the second one that read async from it.
I need to create a third one that generate 20 more.
the newly created threads will run till explicitly stopped. those 20 threads should get "live" data in order to analyze it.
each of the 20 has a unique ID/name. I need to send the relevant data (that the READ thread collect) to the correct thread (of the 20 threads). e.g. if the data include a string with id (in it) of 2 --> I need to send it to thread with the ID =2.
my question is: how should I hold a "pointer" to each of the 20 threads and send it the relevant data? (I can search the id in a runnable list (that will hold the threads)--> but then I need to call to a method "NewData(string)" in order to send the data to the running thread).
How should I do it?
TIA
Paz
You would probably be better to use a Queue to communicate with your threads. You could then put all of the queues in a map for easy access. I would recommend a BlockingQueue.
public class Test {
// Special stop message to tell the worker to stop.
public static final Message Stop = new Message("Stop!");
static class Message {
final String msg;
// A message to a worker.
public Message(String msg) {
this.msg = msg;
}
public String toString() {
return msg;
}
}
class Worker implements Runnable {
private volatile boolean stop = false;
private final BlockingQueue<Message> workQueue;
public Worker(BlockingQueue<Message> workQueue) {
this.workQueue = workQueue;
}
#Override
public void run() {
while (!stop) {
try {
Message msg = workQueue.poll(10, TimeUnit.SECONDS);
// Handle the message ...
System.out.println("Worker " + Thread.currentThread().getName() + " got message " + msg);
// Is it my special stop message.
if (msg == Stop) {
stop = true;
}
} catch (InterruptedException ex) {
// Just stop on interrupt.
stop = true;
}
}
}
}
Map<Integer, BlockingQueue<Message>> queues = new HashMap<>();
public void test() throws InterruptedException {
// Keep track of my threads.
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 20; i++) {
// Make the queue for it.
BlockingQueue<Message> queue = new ArrayBlockingQueue(10);
// Build its thread, handing it the queue to use.
Thread thread = new Thread(new Worker(queue), "Worker-" + i);
threads.add(thread);
// Store the queue in the map.
queues.put(i, queue);
// Start the process.
thread.start();
}
// Test one.
queues.get(5).put(new Message("Hello"));
// Close down.
for (BlockingQueue<Message> q : queues.values()) {
// Stop each queue.
q.put(Stop);
}
// Join all threads to wait for them to finish.
for (Thread t : threads) {
t.join();
}
}
public static void main(String args[]) {
try {
new Test().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
I am trying to implement nodes talking to each other in Java. I am doing this by creating a new thread for every node that wants to talk to the server.
When the given number of nodes, i.e. that many threads have been created, have connected to the server I want each thread to execute their next bit of code after adding to the "sharedCounter".
I think I need to use 'locks' on the shared variable, and something like signalAll() or notifyAll() to get all the threads going, but I can't seem to make clear sense of exactly how this works or to implement it.
Any help explaining these Java concepts would be greatly appreciated :D
Below is roughly the structure of my code:
import java.net.*;
import java.io.*;
public class Node {
public static void main(String[] args) {
...
// Chooses server or client launchers depend on parameters.
...
}
}
class sharedResource {
private int sharedCounter;
public sharedResource(int i) {
sharedCounter = i;
}
public synchronized void incSharedCounter() {
sharedCounter--;
if (sharedCounter == 0)
// Get all threads to do something
}
}
class Server {
...
for (int i = 0; i < numberOfThreads; i++) {
new serverThread(serverSocket.accept()).start();
}
...
sharedResource threadCount = new sharedResource(numberOfThreads);
...
}
class serverThread extends Thread {
...
//some code
Server.threadCount.incSharedCounter();
// Some more code to run when sharedCounte == 0
...
}
class Client {
...
}
// Get all threads to do something
Threads (or rather Runnables, which you should implement rather than extending Thread) have a run method that contains the code they are expected to execute.
Once you call Thread#start (which in turn calls Runnable#run), the thread will start doing exactly that.
Since you seem to be new to multi-threading in Java, I recommend that you read an introduction to the Concurrency Utility package, that has been introduced in Java5 to make it easier to implement concurrent operations.
Specifically what you seem to be looking for is a way to "pause" the operation until a condition is met (in your case a counter having reached zero). For this, you should look at a CountDownLatch.
Indeed, the subject is broad, but I'll try to explain the basics. More details can be read from various blogs and articles. One of which is the Java trail.
It is best to see each thread as being runners (physical persons) that run alongside each other in a race. Each runner may perform any task while running. For example, take a cup of water from a table at a given moment in the race. Physically, they cannot both drink from the same cup at once, but in the virtual world, it is possible (this is where the line is drawn).
For example, take again two runners; each of them has to run back and forth a track, and push a button (shared by the runners) at each end for 1'000'000 times, the button is simply incrementing a counter by one each time. When they completed their run, what would be the value of the counter? In the physical world, it would be 2'000'000 because the runners cannot push the button at the same time, they would wait for the first one to leave first... that is unless they fight over it... Well, this is exactly what two threads would do. Consider this code :
public class ThreadTest extends Thread {
static public final int TOTAL_INC = 1000000;
static public int counter = 0;
#Override
public void run() {
for (int i=0; i<TOTAL_INC; i++) {
counter++;
}
System.out.println("Thread stopped incrementing counter " + TOTAL_INC + " times");
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new ThreadTest();
Thread t2 = new ThreadTest();
t1.start();
t2.start();
t1.join(); // wait for each thread to stop on their own...
t2.join(); //
System.out.println("Final counter is : " + counter + " which should be equal to " + TOTAL_INC * 2);
}
}
An output could be something like
Thread stopped incrementing counter 1000000 times
Thread stopped incrementing counter 1000000 times
Final counter is : 1143470 which should be equal to 2000000
Once in a while, the two thread would just increment the same value twice; this is called a race condition.
Synchronizing the run method will not work, and you'd have to use some locking mechanism to prevent this from happening. Consider the following changes in the run method :
static private Object lock = new Object();
#Override
public void run() {
for (int i=0; i<TOTAL_INC; i++) {
synchronized(lock) {
counter++;
}
}
System.out.println("Thread stopped incrementing counter " + TOTAL_INC + " times");
}
Now the expected output is
...
Final counter is : 2000000 which should be equal to 2000000
We have synchronized our counter with a shared object. This is like putting a queue line before only one runner can access the button at once.
NOTE : this locking mechanism is called a mutex. If a resource can be accessed by n threads at once, you might consider using a semaphore.
Multithreading is also associated with deadlocking. A deadlock is when two threads mutually waits for the other to free some synchronized resource to continue. For example :
Thread 1 starts
Thread 2 starts
Thread 1 acquire synchronized object1
Thread 2 acquire synchronized object2
Thread 2 needs to acquire object2 for continuing (locked by Thread 1)
Thread 1 needs to acquire object1 for continuing (locked by Thread 2)
Program hangs in deadlock
While there are many ways to prevent this from happening (it depends on what your threads are doing, and how they are implemented...) You should read about that particularly.
NOTE : the methods wait, notify and notifyAll can only be called when an object is synchronized. For example :
static public final int TOTAL_INC = 10;
static private int counter = 0;
static private Object lock = new Object();
static class Thread1 extends Thread {
#Override
public void run() {
synchronized (lock) {
for (int i=0; i<TOTAL_INC; i++) {
try {
lock.wait();
counter++;
lock.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class Thread2 extends Thread {
#Override
public void run() {
synchronized (lock) {
for (int i=0; i<TOTAL_INC; i++) {
try {
lock.notify();
counter--;
lock.wait();
} catch (InterruptedException e) {
/* ignored */
}
}
}
}
}
Notice that both threads are running their for...loop blocks within the synchronized block. (The result of counter == 0 when both threads end.) This can be achieved because they "let each other" access the synchronized resource via the resource's wait and notify methods. Without using those two methods, both threads would simply run sequentially and not concurrently (or more precisely, alternately).
I hope this shed some light about threads (in Java).
** UPDATE **
Here is a little proof of concept of everything discussed above, using the CountDownLatch class suggested by Thilo earlier :
static class Server {
static public final int NODE_COUNT = 5;
private List<RunnableNode> nodes;
private CountDownLatch startSignal;
private Object lock = new Object();
public Server() {
nodes = Collections.synchronizedList(new ArrayList<RunnableNode>());
startSignal = new CountDownLatch(Server.NODE_COUNT);
}
public Object getLock() {
return lock;
}
public synchronized void connect(RunnableNode node) {
if (startSignal.getCount() > 0) {
startSignal.countDown();
nodes.add(node);
System.out.println("Received connection from node " + node.getId() + " (" + startSignal.getCount() + " remaining...)");
} else {
System.out.println("Client overflow! Refusing connection from node " + node.getId());
throw new IllegalStateException("Too many nodes connected");
}
}
public void shutdown() {
for (RunnableNode node : nodes) {
node.shutdown();
}
}
public void awaitAllConnections() {
try {
startSignal.await();
synchronized (lock) {
lock.notifyAll(); // awake all nodes
}
} catch (InterruptedException e) {
/* ignore */
shutdown(); // properly close any connected node now
}
}
}
static class RunnableNode implements Runnable {
private Server server;
private int id;
private boolean working;
public RunnableNode(int id, Server server) {
this.id = id;
this.server = server;
this.working = true;
}
public int getId() {
return id;
}
public void run() {
try {
Thread.sleep((long) (Math.random() * 5) * 1000); // just wait randomly from 0 to 5 seconds....
synchronized (server.getLock()) {
server.connect(this);
server.getLock().wait();
}
if (!Thread.currentThread().isAlive()) {
throw new InterruptedException();
} else {
System.out.println("Node " + id + " started successfully!");
while (working) {
Thread.yield();
}
}
} catch (InterruptedException e1) {
System.out.print("Ooop! ...");
} catch (IllegalStateException e2) {
System.out.print("Awwww! Too late! ...");
}
System.out.println("Node " + id + " is shutting down");
}
public void shutdown() {
working = false; // shutdown node here...
}
}
static public void main(String...args) throws InterruptedException {
Server server = new Server();
for (int i=0; i<Server.NODE_COUNT + 4; i++) { // create 4 more nodes than needed...
new Thread(new RunnableNode(i, server)).start();
}
server.awaitAllConnections();
System.out.println("All connection received! Server started!");
Thread.sleep(6000);
server.shutdown();
}
This is a broad topic. You might try reading through the official guides for concurrency (i.e. threading, more or less) in Java. This isn't something with cut-and-dried solutions; you have to design something.