wait and notifyall waiting for other thread - java

I am doing the chef, bread, and customer scenario in Java with thread. So basically the chef makes a bread, the customer eats it, the chef makes more. The maximum is 20. The chef stop making bread when there are 20. The customer stop eating when there is none left. But everytime I use notifyall, it wait four seconds before the customer eat it(supposed to make 3 more breads).
Here is the code for run in the Chef class(implements runnable)
public void run(){
int id = 0;
while(true){
if(Basket.breadList.size() == 20){
synchronized(Basket.breadList){
try {
Basket.breadList.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Bread bread = new Bread(id);
System.out.println("Bread " + id + " had just been made. ");
synchronized(Basket.breadList){
Basket.breadList.notifyAll();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
id++;
}
}
}
Here is the code for Customer:
public void run(){
int id;
while(true){
if(Basket.breadList.size() == 0){
synchronized(Basket.breadList){
try {
Basket.breadList.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
id = Basket.breadList.get(Basket.breadList.size()-1).id;
Basket.breadList.remove(Basket.breadList.size()-1);
System.out.println("Bread " + id + " had just been eaten. ");
synchronized(Basket.breadList){
Basket.breadList.notifyAll();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Here is the code in the controller:
public static void main(String[] args) {
Chef chef = new Chef();
Customer customer = new Customer();
Thread t1 = new Thread(chef);
Thread t2 = new Thread(customer);
t1.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
}
Basket.breadList is just an arraylist of breads.
please help. Much appreciated!

After your Customer eats any bread whatsoever, it always waits 4 seconds. There is nothing to prevent this wait (typically some if () should be in place).
Rule: never sleep() unconditionally, unless you absolutely sure this is how it is supposed to be. You always sleep() because there is nothing else to accomplish and probably will not be for a while. So you need to check if there is.
Also, notifyAll() is typically done immediately after some prior action that makes things available for other threads to process.
Rule: call notifyAll() on a container immediately after you put something in it.
It is also not clear, in which code and at what time Chef adds the Bread to the basket. I assume bread adds itself in its own constructor - if so, it is an anti-pattern. Keep bread simple and healthy, it will taste better this way. Make Chef do the work. I would freak out if, while kneading and baking itself bread crawls into the basket.
Generally speaking, try to write your code exactly as actors in real world would act. Would Chef notify customer basket is not empty? When? Would customer notify Chef when basket is empty? When? When does either of them wait?

Your code is not locking effectively, so that while one thread is working the other can tamper with the data. Here's an example showing a better way for the backer to bake a loaf of bread, then wait while the bread supply is maxed out, then add the loaf to the inventory:
try {
while (true) {
Thread.sleep(4000);
Bread bread = new Bread(id++);
synchronized(Basket.breadList) {
while (Basket.breadList.size() == 20) {
Basket.breadList.wait();
}
Basket.breadList.add(bread);
Basket.breadList.notifyAll();
}
}
} catch (InterruptedException e) {
}
The wait method releases the lock, then re-acquires the lock before it can exit. Since this example holds the lock while it is checking and acting, once the inner while loop is exited from it is certain that the breadList contains less than 20 items. The customer should be rewritten similarly.
This version waits in a loop while holding the lock, checking the condition after emerging from the wait, because something may have changed while your thread didn't have the lock.
Also, just because your thread woke up doesn't mean you got a notification. The wait method can exit without having received a notification. See the Oracle tutorial for how to use wait and notify.
The only way for your thread to know what the size of the list really is is to check it while holding the lock, otherwise it could be changing on you (the other thread can be swapped in and change something in between your check and whatever action you take), resulting in the first thread basing its decisions on possibly stale information.
Likewise your customer shouldn't be removing something from the shared list without holding the lock on it. ArrayList is not threadsafe, also you don't want the state to change in between removing an item and sending the notification. If you are removing something from the list and then want to perform a notification, acquire the lock, then do the removal and notify together while holding the lock.
Don't hold a lock while sleeping, it's pointless and bad for performance. It would be better in this example, if you want to simulate needing time to create bread, for the sleep to come before the call to the Bread constructor.
The way your code swallows InterruptedException doesn't help your thread actually exit cleanly once interrupted. If you catch the InterruptedException outside the while (true) loop then the thread will respond to interruption by actually quitting its work and terminating.
The baker and customer should not be in charge of locking, it's confusing and makes it harder to understand how multithreading is applicable to real-life situations. Use a queue here, making the baker a producer and the customer a consumer. You have a shared data structure already, the arrayList, but you chose a data structure that isn't threadsafe and can't do blocking, the shared data structure needs to be in charge of protecting its own integrity. That way the roles are much clearer, with the locking, waiting, and notifying taking place in the shared data structure and not in the threads. Using a blocking queue from the java.util.concurrent package would be a good choice here, or write your own if you want the experience, it should be do-able once you read the linked tutorial. Once you use a separate queue the run method for the baker becomes:
public void run() {
try {
int id = 0;
while (true) {
Thread.sleep(4000);
queue.put(new Bread(id++));
}
} catch (InterruptedException e) {
}
}
while the queue's put method would be
public synchronized void put(Bread b) throws InterruptedException {
while (breadList.size() == 20) {
wait();
}
breadList.add(b);
notifyAll();
}
assuming that breadList is a private instance member of the Queue.

Related

About Thread's wait()/ notify

I was trying to write an example on how to use wait() and notify(), but seems that the wait() can't be notified
public class Transfer {
private int[] data;
private volatile int ptr;
private final Object lock = new Object();
public Transfer(int[] data) {
this.data = data;
this.ptr = 0;
}
public void send() {
while (ptr < data.length) {
synchronized (lock) {
try {
System.out.println("-----wait");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
ptr++;
}
}
}
public void receive() {
while (ptr < data.length) {
synchronized (lock) {
System.out.println("current is " + data[ptr]);
System.out.println("-----notify");
lock.notifyAll();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
////in main()
int[] data = new int[] { 111, 222, 333, 444, 555, 666, 777, 888, 999, 000 };
Transfer tf = new Transfer(data);
Thread t1 = new Thread(() -> {
tf.receive();
});
Thread t2 = new Thread(() -> {
tf.send();
});
t2.start();
t1.start();
but the result is :
-----wait
current is 111
-----notify
current is 111
-----notify
[endless repeat]
this is not what I expected, it should be :
current is 111
current is 222...
The problem with your code specifically is that you are keeping your locks way too long.
I'll first explain how wait/notify works, which is intricately connected with the concept of the monitor (synchronized), then how to do it right, and then as an encore, that you probably don't want to use this at all, it's too low level.
How does 'synchronized' work
When you write synchronized(x) you acquire the monitor - this operation can do one of three things. In all cases, x is a reference, so the reference is followed, it's about the object you find by following it.
If the reference is null, this immediately throws NPE.
If the object x points at has no current monitor, this thread becomes the monitor, the monitor count becomes 1, and code continues.
If the object x points at has a monitor but it is this thread, then the monitor count is incremented and code continues.
If the object x points at has a monitor but it is another thread, the thread will block until the monitor becomes available. Once it is available, some unfair dice show up, are rolled, and determine which of all threads 'fighting' to acquire the monitor will acquire it. Unfair in the sense that there are no guarantees made and the JVM is free to use any algorithm it wants to decide who 'wins'. If your code depends on fairness or some set order, your code is broken.
Upon reaching the } of the synchronized block, the monitor count is decremented. If it hits 0, the monitor is released (and the fight as per #4 starts, if other threads are waiting). In other words, locks are 're-entrant' in java. A thread can write synchronized(a){synchronized(a){}} and won't deadlock with itself.
Yes, this establishes comes-before stuff as per the Java Memory Model: Any fights arbitrated by a synchronized block will also ensure any writes by things that clearly came before (as established by who wins the fight) are observable by anything that clearly came after.
A method marked as 'synchronized' is effectively equivalent to wrapping the code in synchronized(this) for instance methods, and synchronized(MyClass.class) for static methods.
Monitors are not released and cannot be changed in java code* except via that } mechanism; (there is no public Thread getMonitor() {..} in j.l.Object or anywhere else) - in particular if the thread blocks for any other reason, including Thread.sleep, the monitor status does not change - your thread continues to hold on to it and thus stops all other threads from acquiring it. With one exception:
So how does wait/notify factor into this?
to wait/notify on x you MUST hold the monitor. this: x.notify();, unless it is wrapped in a synchronized(x) block, does not work.
When you wait(), the monitor is released, and the monitor count is remembered. a call to wait() requires 2 things to happen before it can continue: The 'wait' needs to be cancelled, either via a timeout, or an interrupt, or via a notify(All), and the thread needs to acquire that monitor again. If done normally (via a notify), by definition this is a fight, as whomever called notify neccessarily is still holding that monitor.
This then explains why your code does not work - your 'receiver' snippet holds on to the monitor while it sleeps. Take the sleep outside of the synchronized.
How do you use this, generally
The best way to use wait/notifyAll is not to make too many assumptions about the 'flow' of locking and unlocking. Only after acquiring the monitor, check some status. If the status is such that you need to wait for something to happen, then and only then start the wait() cycle. The thread that will cause that event to happen will first have to acquire the monitor and only then set steps to start the event. If this is not possible, that's okay - put in a failsafe, make the code that wait()s use a timeout (wait(500L) for example), so that if things fail, the while loop will fix the problem. Furthermore, there really is no good reason to ever use notify so forget that exists. notify makes no guarantees about what it'll unlock, and given that all threads that use wait ought to be checking the condition they were waiting for regardless of the behaviour of wait, notifyAll is always the right call to make.
So, it looks like this... let's say we're waiting for some file to exist.
// waiting side:
Path target = Paths.get("/file-i-am-waiting-for.txt");
synchronized (lock) {
while (!Files.isRegularFile(target)) {
try {
lock.wait(1000L);
} catch (InterruptedException e) {
// this exception occurs ONLY
// if some code explicitly called Thread.interrupt()
// on this thread. You therefore know what it means.
// usually, logging interruptedex is wrong!
// let's say here you intended it to mean: just exit
// and do nothing.
// to be clear: Interrupted does not mean:
// 'someone pressed CTRL+C' or 'the system is about to shutdown'.
return;
}
}
performOperation(target);
}
And on the 'file creation' side:
Path tgt = Paths.get("/file-i-am-waiting-for.txt");
Path create = tgt.getParent().resolve(tgt.getFileName() + ".create");
fillWithContent(create);
synchronized (lock) {
Files.move(create, tgt, StandardOpenOption.ATOMIC_MOVE);
lock.notifyAll();
}
The 'sending' (notifying) side is very simple, and note how we're using the file system to ensure that if the tgt file exists at all, it's fully formed and not a half-baked product. The receiving side uses a while loop: the notifying is itself NOT the signal to continue; it is merely the signal to re-check for the existence of this file. This is almost always how to do this stuff. Note also how all code involved with that file is always only doing things when they hold the lock, thus ensuring no clashes on that part.
But.. this is fairly low level stuff
The java.util.concurrent package has superior tooling for this stuff; for example, you may want a latch here, or a ReadWriteLock. They tend to outperform you, too.
But even juc is low level. Generally threading works best if the comm channel used between threads is inherently designed around concurrency. DBs (with a proper transaction level, such as SERIALIZABLE), or message buses like rabbitmq are such things. Why do you think script kiddies fresh off of an 8 hour course on PHP can manage to smash a website together that actually does at least hold up, thread-wise, even if it's littered with security issues? Because PHP enforces a model where all comms run through a DB because PHP is incapable of anything else in its basic deployment. As silly as these handcuffs may sound, the principle is solid, and can be applied just as easily from java.
*) sun.misc.Unsafe can do it, but it's called Unsafe for a reason.
Some closing best practices
Locks should be private; this is a rule broken by most examples and a lot of java code. You've done it right: if you're going to use synchronized, it should probably be on lock, which is private final Object lock = new Object();. Make it new Object[0] if you need it to be serializable, which arrays are, and Objects aren't.
if ever there is code in your system that does: synchronized(a) { synchronized (b) { ... }} and also code that odes: synchronized(b) { synchronized (a) { ... }} you're going to run into a deadlock at some point (each have acquired the first lock and are waiting for the second. They will be waiting forever. Be REAL careful when acquiring more than one monitor, and if you must, put in a ton of effort to ensure that you always acquire them in the same order to avoid deadlocks. Fortunately, jstack and such (tools to introspect running VMs) can tell you about deadlocks. The JVM itself, unfortunately, will just freeze in its tracks, dead as a doornail, if you deadlock it.
class Transfer {
private int[] data;
private volatile int ptr;
private final Object lock = new Object();
public Transfer(int[] data) {
this.data = data;
this.ptr = 0;
}
public void send() {
while (ptr < data.length) {
synchronized (lock) {
try {
System.out.println("-----wait");
lock.notifyAll();
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
ptr++;
}
}
}
public void receive() {
while (ptr < data.length) {
synchronized (lock) {
System.out.println("current is " + data[ptr]);
System.out.println("-----notify");
try {
lock.notifyAll();
lock.wait();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
"Thread.sleep" does not release the lock. So you need "lock.wait" to release the lock and let other thread proceed. Then after "send" increment the pointer, it should also notify so that other thread who is stuck at receive can now proceed.

How to interrupt thread to do work and then sleep after doing work?

I want to have a thread which does some I/O work when it is interrupted by a main thread and then go back to sleep/wait until the interrupt is called back again.
So, I have come up with an implementation which seems to be not working. The code snippet is below.
Note - Here the flag is a public variable which can be accessed via the thread class which is in the main class
// in the main function this is how I am calling it
if(!flag) {
thread.interrupt()
}
//this is how my thread class is implemented
class IOworkthread extends Thread {
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
} catch (InterruptedException e) {
flag = true;
try {
// doing my I/O work
} catch (Exception e1) {
// print the exception message
}
}
}
}
}
In the above snippet, the second try-catch block catches the InterruptedException. This means that both of the first and second try-catch block are catching the interrupt. But I had only called interrupt to happen during the first try-catch block.
Can you please help me with this?
EDIT
If you feel that there can be another solution for my objective, I will be happy to know about it :)
If it's important to respond fast to the flag you could try the following:
class IOworkthread extends Thread {//implements Runnable would be better here, but thats another story
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
}
catch (InterruptedException e) {
flag = true;
}
//after the catch block the interrupted state of the thread should be reset and there should be no exceptions here
try {
// doing I/O work
}
catch (Exception e1) {
// print the exception message
// here of course other exceptions could appear but if there is no Thread.sleep() used here there should be no InterruptedException in this block
}
}
}
}
This should do different because in the catch block when the InterruptedException is caught, the interrupted flag of the thread is reset (at the end of the catch block).
It does sound like a producer/consumer construct. You seem to kind of have it the wrong way around, the IO should be driving the algorithm. Since you stay very abstract in what your code actually does, I'll need to stick to that.
So let's say your "distributed algorithm" works on data of type T; that means that it can be described as a Consumer<T> (the method name in this interface is accept(T value)). Since it can run concurrently, you want to create several instances of that; this is usually done using an ExecutorService. The Executors class provides a nice set of factory methods for creating one, let's use Executors.newFixedThreadPool(parallelism).
Your "IO" thread runs to create input for the algorithm, meaning it is a Supplier<T>. We can run it in an Executors.newSingleThreadExecutor().
We connect these two using a BlockingQueue<T>; this is a FIFO collection. The IO thread puts elements in, and the algorithm instances take out the next one that becomes available.
This makes the whole setup look something like this:
void run() {
int parallelism = 4; // or whatever
ExecutorService algorithmExecutor = Executors.newFixedThreadPool(parallelism);
ExecutorService ioExecutor = Executors.newSingleThreadExecutor();
// this queue will accept up to 4 elements
// this might need to be changed depending on performance of each
BlockingQueue<T> queue = new ArrayBlockingQueue<T>(parallelism);
ioExecutor.submit(new IoExecutor(queue));
// take element from queue
T nextElement = getNextElement(queue);
while (nextElement != null) {
algorithmExecutor.submit(() -> new AlgorithmInstance().accept(nextElement));
nextElement = getNextElement(queue);
if (nextElement == null) break;
}
// wait until algorithms have finished running and cleanup
algorithmExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.YEARS);
algorithmExecutor.shutdown();
ioExecutor.shutdown(); // the io thread should have terminated by now already
}
T getNextElement(BlockingQueue<T> queue) {
int timeOut = 1; // adjust depending on your IO
T result = null;
while (true) {
try {
result = queue.poll(timeOut, TimeUnits.SECONDS);
} catch (TimeoutException e) {} // retry indefinetely, we will get a value eventually
}
return result;
}
Now this doesn't actually answer your question because you wanted to know how the IO thread can be notified when it can continue reading data.
This is achieved by the limit to the BlockingQueue<> which will not accept elements after this has been reached, meaning the IO thread can just keep reading and try to put in elements.
abstract class IoExecutor<T> {
private final BlockingQueue<T> queue;
public IoExecutor(BlockingQueue<T> q) { queue = q; }
public void run() {
while (hasMoreData()) {
T data = readData();
// this will block if the queue is full, so IO will pause
queue.put(data);
}
// put null into queue
queue.put(null);
}
protected boolean hasMoreData();
protected abstract T readData();
}
As a result during runtime you should at all time have 4 threads of the algorithm running, as well as (up to) 4 items in the queue waiting for one of the algorithm threads to finish and pick them up.

notifyAll in java

Is it wrong to use notifyAll() inside the loop in a multiple producer-consumer problem in Java?
Here is the code snippet which I am talking about.
public void run() {
while(producer_counter <= 64) {
synchronized(list) {
threadId1 = "Producer " + Thread.currentThread().getName();
//Buffer size is 8
while(list.size() >= 8) {
System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
System.out.println(threadId1+ " found the buffer is full & waiting for a Consumer to consume.");
System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
try {
list.wait();
list.notifyAll();
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
System.out.println(threadId1+ " produced item " + producer_counter);
//Adding the items produced to the list.
list.add(producer_counter);
producer_counter++;
//Invoking notify
list.notifyAll();
}
}
}
}
notifyAll() is to notify all parties about changes in the state of the synchronized object. The first call, which is after wait(), is redundant because no state change happened. This call does not make the program wrong, but only causes waste of CPU cycles: when the buffer is full, notifyAll() is called and all other threads, waiting for the buffer's availability, go to processor only to call notifyAll() again and then call wait(). As a result, one processor in your machine will be always busy making unnecessary work.
BTW, you should not catch InterruptedException (or any other exception) if you don't know why it happened and what to do about it. If, like here, you cannot write public void run() throws InterruptedException, then write
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
Instead of RuntimeException, better declare your own unchecked exception.
You should not use list.notifyAll() in while loop.After adding the items produced to the list list.add(producer_counter) you can use notify all.
// producer thread waits while list is full
while (list.size() >= 8){
list.wait();
}
// to insert the jobs in the list and plus 1 the counter
list.add(producer_counter);
producer_counter++;
// notifies the consumer threads that now it can start
//consuming
list.notifyAll();

Thread exercise - Help me understand

Well, I am a student in the second semester, and now we are going trough threads. I mostly get it, but something is off about one of my exercises and I can't quite understand it.
"In a bakery shop, you often have to take a number when you arrive at the shop and then wait until it is your
turn (with the right number)."
Im going to copy-paste the methods in the monitor where I think the problem might be.
private NumberDispenser(){
nextNoToTake=1;
nextNoToServe=0;
}
public static NumberDispenser accessDispenser(){
if(theOne == null){
theOne = new NumberDispenser();
}
return theOne;
}
#Override
public synchronized void takeNextNumber() {
int currNo = nextNoToTake;
nextNoToTake++;
notifyAll();
System.out.println("No:"+currNo+" has been taken|nextNoToServe:"+nextNoToServe);
while(currNo != nextNoToServe)
{try {
wait();
} catch (InterruptedException e) {}
}
System.out.println("No:"+currNo+" has been served");
notify();
}
#Override
public synchronized int nextCustomer() {//Serves the current customer and goes to the next one
System.out.println("Clerk is ready to deal with a new customer");
while((nextNoToServe)>=nextNoToTake-1)
try {
wait();
} catch (InterruptedException e) {}
nextNoToServe++;
notifyAll();
System.out.println("Now serving No:"+(nextNoToServe));
return nextNoToServe;
}
This is the monitor class. There are two more , for the Customer and for the Clerk , and one more for testing. The customer class has Thread.sleep to simulate time for browsing then goes into dispenser.takeNextNumber();, after which it should finish and the thread responsible for it should die by itself(in the main class).Clerk loops dispenser.nextCustomer() endlessly with a delay.The main method creates , in separate for loops, a number of customers and their threads , and a number of clerks and their threads.
///// This is copy pasted from the requirements.
Customer arrivals and clerk servings are simulated by threads.
Implement as a monitor a class NumberDispencer that implements the interface TakeANumber.
Hint: you could define the two instance variables
private int nextNumberToTake = 1;
private int nextNumberToServe = 1;
Implement two thread classes:
 A thread class which simulates customer taking a number and being served
 A thread class that simulates clerk serving, that is getting the next customer number and then make
service.
Implement a class with a main method to simulate a bakery shop with e.g. two serving clerks and ten
customers.
/////
I have almost fixed the code. The problem was in the condition of the while loops. Now it works almost as intended, but it skips over the first customer. Only the first customer is skipped, then it all goes how it should.
console output
I can see one place where it is broken.
Hint: Suppose that there is one server and one customer, and the server calls nextCustomer() before a customer arrives. What will wake it up when the customer arrives?
Also, this statement is a hack.
if (nextNoToServe == 0)
nextNoToServe = 1;
That should be dealt with by initializing the instance variables to appropriate values; e.g. in the constructor.

java program a infinite loop in thread cause hundred percent cpu

I am quite new to Threads in Java, I am using an API which is using thread internally and listening data from the counter party, I am putting this data in an queue for further processing. I have created another Thread which is continuously reading this queue for retrieving data and processing and to write the results into text file. I am using while(true) statement to run infinite loop in thread this cause a hundred per cent of CPU usage and if I use sleep(10) in it add up latency which keep on increasing with time as I am receiving about 20 data item in one second.
public void run() {
while(true) {
try { Thread.sleep(10); }
catch (InterruptedException e2) { // TODO Auto-generated catch block
e2.printStackTrace();
}
if (!(queue.isEmpt())) {
Tick quote=queue.take();
processTuple(quote);
}
} // end while(true)
} // end run()
Could anyone suggest me solution where I can reduce CPU usage without adding latency.
Check out ArrayBlockingQueue.
EDIT:
Example of how to use a queue based on your code:
LinkedBlockingQueue<Tick> queue;
public void run() {
while (true) {
// No need to check the queue. No need to sleep().
// take() will wait until there's anything available
Tick quote = queue.take();
processTuple(quote);
}
}
Ya. Use a BlockingQueue implementation instead of busy- wait. while(true) will keep scheduling the thread.
Use queue implementations instead of Threads. See this link to know more about queue implementations. You can use ArrayBlockingQueue.
You may change your code something like this:
BlockingQueue<Tick> queue = ..
public void run()
{
for (Tick quote; quote = queue.take(); )
{
if (quote == someSpecialObjectToIndicateStop)
break; // To stop this thread Or you may catch InterruptedException
processTuple(quote);
}
}
See BlockingQueue documentation here

Categories

Resources