I have to create two Threads which have to poll and object from a queue in 2 seconds intervals.
The first Thread poll and object then wait and notify the second one to poll the object from it's queue.
I read all about wait and notify but nothing works with me.
Any sugestions?
First thread:
public class SouthThread extends Thread {
private Queue<Car> q = new LinkedList<Car>();
public void CreateQueue() {
Scanner input = new Scanner(System.in);
for (int i = 0; i < 2; i++) {
Car c = new Car();
System.out.println("Enter registration number: ");
String regNum = input.nextLine();
c.setRegNum(regNum);
q.offer(c);
}
}
public int getQueueSize() {
return q.size();
}
#Override
public void run() {
while (q.size() != 0)
try {
while (q.size() != 0) {
synchronized (this) {
System.out.print("The car with registration number: ");
System.out.print(q.poll().getRegNum());
System.out
.println(" have passed the bridge from the south side.");
this.wait(2000);
notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Second thread:
public class NorthThread extends Thread {
private Queue<Car> q = new LinkedList<Car>();
public void CreateQueue() {
Scanner input = new Scanner(System.in);
for (int i = 0; i < 2; i++) {
Car c = new Car();
System.out.println("Enter registration number: ");
String regNum = input.nextLine();
c.setRegNum(regNum);
q.offer(c);
}
}
public int getQueueSize() {
return q.size();
}
#Override
public void run() {
try {
while (q.size() != 0) {
synchronized (this) {
System.out.print("The car with registration number: ");
System.out.print(q.poll().getRegNum());
System.out
.println(" have passed the bridge from the north side.");
this.wait(2000);
notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Main Thread:
public class Main {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
SouthThread tSouthThread = new SouthThread();
NorthThread tNorthThread = new NorthThread();
tSouthThread.CreateQueue();
tNorthThread.CreateQueue();
System.out.println(tSouthThread.getQueueSize());
tSouthThread.start();
tNorthThread.start();
}
}
It seems that what you basically want to achieve is a system that alternates control between two independent units so that each of the units gets some time to process followed by a two second waiting period (or vice versa).
There are two main ways you could achieve this:
Using a central control
With autonomous communicating agents
The first approach is a bit easier. Here, you have a central "master" component which takes care of coordinating who gets the processing time and also implements the wait times. For that approach, the two independent units do not even have to be Threads:
public class South {
private Queue<Car> q = new LinkedList<Car>();
public void CreateQueue() { ... }
public void poll() {
System.out.print("The car with registration number: ");
System.out.print(q.poll().getRegNum());
System.out.println(" have passed the bridge from the South side.");
}
}
public class North {
private Queue<Car> q = new LinkedList<Car>();
public void CreateQueue() { ... }
public void poll() {
System.out.print("The car with registration number: ");
System.out.print(q.poll().getRegNum());
System.out.println(" have passed the bridge from the North side.");
}
}
// This is the "master" class
public class Main {
public static void main(String[] args) {
South south = new South();
North north = new North();
south.CreateQueue();
north.CreateQueue();
boolean done = false;
while (!done) {
try {
Thread.sleep(2000);
} (catch InterruptedException) { /* TODO */ }
north.poll();
try {
Thread.sleep(2000);
} (catch InterruptedException) { /* TODO */ }
south.poll();
}
}
}
Note that North and South do not inherit from Thread here, i.e., they are just plain old objects.
(However, if your program is more complex and North/South are only one part of it, you might want to make Main(!) a separate thread and put the above while-loop inside the thread's run method, so that the rest of the program can run concurrently.)
In the second approach, you don't have such a central control component, but the both North and South run in their own separate threads. This then requires that they coordinate who's allowed to process by communicating with each other.
public class SouthThread extends Thread {
protected Queue<Car> q = new LinkedList<Car>();
protected North north;
public void CreateQueue() { ... }
public void poll() { ... }
public void run() {
boolean done = false;
while (!done) {
// wait two seconds
try {
Thread.sleep(2000);
} (catch InterruptedException) { /* TODO */ }
// process one element from the queue
poll();
// notify the other thread
synchronized (north) {
north.notifyAll();
}
// wait until the other thread notifies this one
try {
synchronized (this) {
wait();
}
} (catch InterruptedException) { /* TODO */ }
}
}
}
public class NorthThread extends Thread {
protected Queue<Car> q = new LinkedList<Car>();
protected South south;
public void CreateQueue() { ... }
public void poll() { ... }
public void run() {
boolean done = false;
while (!done) {
// wait two seconds
try {
Thread.sleep(2000);
} (catch InterruptedException) { /* TODO */ }
// process one element from the queue
poll();
// notify the other thread
synchronized (south) {
south.notifyAll();
}
// wait until the other thread notifies this one
try {
synchronized (this) {
wait();
}
} (catch InterruptedException) { /* TODO */ }
}
}
}
public class Main {
public static void main(String[] args) throws Exception {
SouthThread tSouthThread = new SouthThread();
NorthThread tNorthThread = new NorthThread();
tSouthThread.north = tNorthThread;
tNorthThread.south = tSouthThread;
tSouthThread.CreateQueue();
tNorthThread.CreateQueue();
tSouthThread.start();
tNorthThread.start();
}
}
A more general remark: since both North and South seem to be doing basically the same, there's probably no need to implement them in two separate classes. Instead, it should be sufficient to have only one class that implements the desired functionality and instantiate it twice:
// We can combine the functionality of North and South
// in a single class
public class NorthSouth {
public void CreateQueue() { ... }
public void poll() { ... }
// etc.
}
public class Main {
public static void main(String[] args) {
NorthSouth north = new NorthSouth();
NorthSouth south = new NorthSouth();
north.CreateQueue();
south.CreateQueue();
// etc.
}
}
wait and notify must refer to the same lock: When you call object.wait(2000) what you're saying is "I'm going to wait here for 2000 millis, or until someone else calls object.notify() where object refers to me"
I still don't completely understand what you want to achieve, but if you simply want two threads that concurrently do:
Do something
Wait 2 seconds
GOTO 1
then you don't need wait/notify at all, you could get around using Thread.sleep() or potentially two instances of java.util.Timer.
But again, I'm not sure I understand correctly. :-(
Related
I have two threads. The first changes the value of variable Data. And second one print the value if its value has changed. I am trying to do that second thread just print each time that the variable's value changed, but I don't reach success. Someone can help me?
thread 1
class someservice{
volatile int data;
Boolean Flag = false;
public void mymethod(){
flag = true;
for (Integer i = 1; i < sheet.getRows(); i++) {
data = someMethod(); //this method when called return a new
//value
}
flag = false;
...
}
}
thread 2
Promise p = task {
try {
while (true) {
if (engineService.getFlag()) {
print(someservice.data);
}else{
break;
}
}
} catch(Throwable t) {
...
}
}
Since you mention Promises, I infer you are familiar with future/ promise in +C++11
in java there is a similar approach, with future callable...
public class HW5 {
public static void main(String[] argv) throws InterruptedException, ExecutionException {
FutureTask<Boolean> myFutureTask = new FutureTask<>(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// implement the logic here and return true if everything was
// ok, false otherwise.
Thread.sleep(5000);
System.out.println("dddd");
return System.currentTimeMillis() % 2 == 0;
}
});
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(myFutureTask);
Boolean result = myFutureTask.get();
System.out.println("Done!");
}
}
FutureTask in a class that takes a callable which can return an Object after its job is done... in Order to execute the Future task you can use a Executor service, especifically calling the method execute, since you need to wait for the thread to do the job then is necessary that you call Future.get, that will basically blocks the main thread until the future is done, to verify the result, just read the variable result..
You could use the notify() and notifyAll() methods within thread. Check out this link: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
public synchronized void guardedJoy() {
// This guard only loops once for each special event, which may not
// be the event we're waiting for.
while(!joy) {
try {
wait();
} catch (InterruptedException e) {}
}
System.out.println("Joy and efficiency have been achieved!");
}
public synchronized notifyJoy() {
joy = true;
notifyAll();
}
You have to look up more data about Concurrent programming,I can tell you now some basics,well,not so so basic,but i will do my best:
Here,you have a Monitor,it is an abstract concept,in resume,a Monitor is a
class with all it's
method using"syncronized"
as modifier, it means,
that only
one thread
can access
the method
at once.So,
in the
monitor is
the variable
that you
want to print,
and the"flag",
that tells you if
the variable
was modified.Finally,
you can
see the
most important thing,the"wait()"and"notify()"methods,
those method
stops the thread,or"play"
them again.
You ask
here in
the printValue() method, if your variable was changed, if the variable was'nt change, put the thead to sleep with the wait() method, and when the other
method changeValue() is executed, the value is modified, and the notify() method is called, waking up the thread, so, doing all this, you can guarantee three things:
Safety: meaning that the threads will do that you want
Absence of deadlock: meaning that the thread that is put to sleep, will be awake in the future.
Mutex: meaning that only one thread is executing the critical code, for example, the op. "++" is not atomic, is Subdivided inside in more the one action, create a local var, read the var, sum, and asign, so, if more than one thread are in the game, the value may not be consecutive, example:
i = 0;
i ++;
output: 1;
output: 2;
output: 3;
output: 5;
output: 4;
output: 7;
That could happen, and even so, that will happen in the next code, because there a more than one thread executing. Well, this is the way to program with several threads, more or less
public class Monitor {
private int value = 0;
public static boolean valueHasChanged = false;
public synchronized int changeValue(int newValue){
this.value = newValue;
Monitor.valueHasChanged = true;
this.notify();
return this.value + 1;
}
public synchronized void printValue(){
while(!Monitor.valueHasChanged){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(this.value);
Monitor.valueHasChanged = false;
}
public static void main(String[] args) {
Monitor ac = new Monitor();
BClass t1 = new BClass(ac);
AClass t2 = new AClass(ac);
t1.start();
t2.start();
}
public int getValue() {
return this.value;
}
}
Now the threads:
public class AClass extends Thread{
private Monitor ac;
public AClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
while(true){
this.ac.printValue();
}
}
}
And finally:
public class BClass extends Thread{
private Monitor ac;
public BClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
int v = 0;
while(true){
this.ac.changeValue(v);
v++; // this sum is not secure, if you want to print an
// ascending order, the code is diferent, I will show in
// above.
}
}
Now, if you want an ordered print:
the monitor will look like:
public class Monitor {
private int value = 0;
public boolean valueHasChanged = false;
private boolean hasPrint = true;
public synchronized void changeValue(int newValue) {
this.value = newValue;
this.valueHasChanged = true;
this.notify();
}
public synchronized void changeValuePlusOne() {
while (!hasPrint) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.value++;
this.valueHasChanged = true;
this.hasPrint = false;
this.notifyAll();
}
public synchronized void printValue() {
while (!this.valueHasChanged) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.value);
this.valueHasChanged = false;
this.hasPrint = true;
this.notifyAll();
}
public static void main(String[] args) {
Monitor ac = new Monitor();
BClass t1 = new BClass(ac);
AClass t2 = new AClass(ac);
t1.start();
t2.start();
}
public int getValue() {
return this.value;
}
}
And the Threads:
public class BClass extends Thread{
private Monitor ac;
public BClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
while(true){
this.ac.changeValuePlusOne();
}
}
}
The other Thread look equals:
public class AClass extends Thread{
private Monitor ac;
public AClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
while(true){
this.ac.printValue();
}
}
}
I have two threads. One is a producer (class Deliver), second is consumer (class Produce). I want to simulate door producer. So producer deliver wood that consumer can produce a door. But i do not real get how to communicate between those two threads. Now when i run my program only wood is delivered but doors are not produced. I do not get why.
public class Deliver implements Runnable {
private static int MAX_STOCKPILE = 15;
private Integer wood;
public Deliver(Integer wood) {
this.wood = wood;
new Thread(this, "Deliver").start();
}
public synchronized void deliver() throws InterruptedException{
Thread.sleep(500);
if (wood < MAX_STOCKPILE) {
wood++;
System.out.println("Wood delivered" + " | Wood stockpile: " + wood);
notify();
}
else {
wait();
}
}
#Override
public void run() {
while (true) {
try {
deliver();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Produce implements Runnable{
private Integer wood;
public Produce(Integer wood) {
this.wood = wood;
new Thread(this, "Produce").start();
}
public synchronized void produce() throws InterruptedException{
Thread.sleep(1000);
if (wood == 10) {
wood -= 10; //produce
System.out.println("Doors produced");
notify();
}
else {
wait();
}
}
#Override
public void run() {
while (true) {
try {
produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Integer wood = 0;
new Deliver(wood);
new Produce(wood);
}
}
Now when i run my program only wood is delivered but doors are not produced. I do not get why
There are multiple issues with your code :
When you mark an instance method as synchronized, any thread entering that method will obtain a lock on this (i.e the instance on which the method was called). Since this in Deliver refers to a Deliver instance and this in Produce refers to a Produce instance, the wait and notify calls are practically useless in this case as they are not interested in the same objects.
The golden rule to remember in Java is that it uses pass-by-value semantics. Primitives and references are therefore always passed by value. While you may assume that both Deliver and Produce will be modifying the same Integer passed to them from main, that is not the case.
That said, I would highly recommend that you consider using something like an ArrayBlockingQueue for solving this instead of reinventing the wheel with wait and notify.
Change
if (wood == 10) {
to
if (wood >= 10) {
in case the thread doesn't catch it when it == 10
Something to note is that Integer is immutable.
When you change the reference to the Integer you are creating a new object which has no relationship to the previous object.
What you want this an object which is shared between the two threads so when you change the value (but not the reference) they are looking at the same value.
e.g.
wood -= 10;
is the same as
wood = Integer.valueOf(wood.intValue() - 10);
I suggest using AtomicInteger and making the reference to it final to ensure you don't accidentally try to change the reference.
As Andrew Jenkins suggests; if you lock, notify/wait on unrelated objects, you don't have any thread safety. Once you have a shared object, you have to lock, notify/wait on that shared object.
I'll throw my solution into the mix, taking into account Peter Lawrey's advice about using AtomicInteger.
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) {
AtomicInteger wood = new AtomicInteger(0);
new Deliver(wood);
new Produce(wood);
}
}
public class Deliver implements Runnable {
private static int MAX_STOCKPILE = 15;
private final AtomicInteger wood;
public Deliver(AtomicInteger wood) {
this.wood = wood;
new Thread(this, "Deliver").start();
}
public void deliver() throws InterruptedException{
Thread.sleep(500);
synchronized(wood) {
if (wood.intValue() < MAX_STOCKPILE) {
wood.addAndGet(1);
System.out.println("Wood delivered" + " | Wood stockpile: " + wood);
wood.notify();
} else {
wood.wait();
}
}
}
#Override
public void run() {
while (true) {
try {
deliver();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Produce implements Runnable{
private final AtomicInteger wood;
public Produce(AtomicInteger wood) {
this.wood = wood;
new Thread(this, "Produce").start();
}
public void produce() throws InterruptedException{
synchronized(wood) {
if (wood.intValue() >= 10) {
wood.addAndGet(-10); //produce
System.out.println("Doors produced");
wood.notify();
}
else {
wood.wait();
}
}
}
#Override
public void run() {
while (true) {
try {
produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Key changes:
We use a mutable object to communicate between threads (AtomicInteger).
We synchronize on the mutable object, not the thread being run.
I have been working on some code, but I need help.
I have created one producer and one consumer, however I need to create multiple consumers who will consume the specific String from the producer e.g. I need a consumer that will consume specifically 'Move Left Hand'.
Contained in the code is the buffer, producer, consumer and the main. I am not sure how to notify the correct consumer and compare the string that needs to be consumed. As it stands I only have one consumer.
public class iRobotBuffer {
private boolean empty = true;
public synchronized String take() {
// Wait until message is
// available.
while (empty) {
try {
wait();
} catch (InterruptedException e) {}
}
// Toggle status.
empty = true;
// Notify producer that
// status has changed.
notifyAll();
return message;
}
public synchronized void put(String message) {
// Wait until message has
// been retrieved.
while (!empty) {
try {
wait();
} catch (InterruptedException e) {}
}
// Toggle status.
empty = false;
// Store message.
this.message = message;
// Notify consumer that status
// has changed.
notifyAll();
}
}
public class iRobotConsumer implements Runnable {
private iRobotBuffer robotBuffer;
public iRobotConsumer(iRobotBuffer robotBuffer){
this.robotBuffer = robotBuffer;
}
public void run() {
Random random = new Random();
for (String message = robotBuffer.take();
! message.equals("DONE");
message = robotBuffer.take()) {
System.out.format("MESSAGE RECEIVED: %s%n", message);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
}
}
public class iRobotProducer implements Runnable {
private iRobotBuffer robotBuffer;
private int number;
public iRobotProducer(iRobotBuffer robotBuffer)
{
this.robotBuffer = robotBuffer;
//this.number = number;
}
public void run() {
String commandInstructions[] = {
"Move Left Hand",
"Move Right Hand",
"Move Both Hands",
};
int no = commandInstructions.length;
int randomNo;
Random random = new Random();
for (int i = 0;
i < commandInstructions.length;
i++) {
randomNo =(int)(Math.random()*no);
System.out.println(commandInstructions[randomNo]);
robotBuffer.put(commandInstructions[i]);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
robotBuffer.put("DONE");
}
}
public class iRobot
{
public static void main(String[] args)
{
iRobotBuffer robotBuffer = new iRobotBuffer();
(new Thread(new iRobotProducer(robotBuffer))).start();
(new Thread(new iRobotConsumer(robotBuffer))).start();
}//main
}//class
The problem is your iRobotBuffer class. It needs to be a queue to support multiple producer / consumers. I've provided the code for such a queue, but java already has an implementation (BlockingDeque<E>).
public class BlockingQueue<T> {
private final LinkedList<T> innerList = new LinkedList<>();
private boolean isEmpty = true;
public synchronized T take() throws InterruptedException {
while (isEmpty) {
wait();
}
T element = innerList.removeFirst();
isEmpty = innerList.size() == 0;
return element;
}
public synchronized void put(T element) {
isEmpty = false;
innerList.addLast(element);
notify();
}
}
As I understand, you would like 3 consumers, one for each move instruction.
You can use an ArrayBlockingQueue from the java.util.concurrent package, in place of the iRobotBuffer class. By the way, you can have a look at the other concurrent collections provided - one may sweet you better.
Then for the consumer, you can peek() at what is in the queue and test if it matches the requirements and then poll().
Essentially, what I want to do is start all my threads, pause them all, then resume them all, using the multithreading approach. I am just looking for a simple solution to this. I'm not sure if I have to use a timer or what. Right now when I run it, the threads are like being executed in random order (I guess the PC is just randomly picking which ones it wants to run at a certain time).
class ChoppingThread extends Thread
{
public void run()
{
for(int j=40;j!=0;j-=10)
System.out.println("Chopping vegetables...("+j+" seconds left)");
}
}
class MixingThread extends Thread
{
public void run()
{
for(int k=60;k!=0;k-=10)
System.out.println("Mixing sauces...("+k+" seconds left)");
}
}
class TenderizingThread extends Thread
{
public void run()
{
for(int j=50;j!=0;j-=10)
System.out.println("Tenderizing meat...("+j+" seconds left)");
}
}
class MultiThreadTasking
{
public static void main (String [] args)
{
ChoppingThread ct = new ChoppingThread();
MixingThread mt = new MixingThread();
TenderizingThread tt = new TenderizingThread();
System.out.println("\nWelcome to the busy kitchen.");
//putting threads into ready state
ct.start();
mt.start();
tt.start();
}
}
There are probably other ways to achieve the same result, but this is the simplest I can come up with off the top of my head (I know, sad isn't it)...
Basically, this is a special Runnable with some additional management functionality.
This basically contains a state flag that indicates the state of the task and a monitor lock
public class ThreadFun {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread thread = new Thread(task);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.pauseTask();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.resumeTask();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.stopTask();
}
public enum TaskState {
Running,
Stopped,
Paused
}
public static class MyTask implements Runnable {
private static final Object PAUSED_LOCK = new Object();
private volatile TaskState state = TaskState.Running;
public void pauseTask() {
if (state == TaskState.Running) {
System.out.println("Paused...");
state = TaskState.Paused;
}
}
public void resumeTask() {
if (state == TaskState.Paused) {
state = TaskState.Running;
synchronized (PAUSED_LOCK) {
PAUSED_LOCK.notifyAll();
}
System.out.println("Resumed...");
}
}
public void stopTask() {
if (state == TaskState.Running || state == TaskState.Paused) {
state = TaskState.Stopped;
System.out.println("Stopped...");
}
}
public boolean isStopped() {
return state == TaskState.Stopped;
}
public boolean isPaused() {
return state == TaskState.Paused;
}
protected void doPause() {
synchronized (PAUSED_LOCK) {
while (isPaused()) {
try {
PAUSED_LOCK.wait();
} catch (InterruptedException ex) {
}
}
}
}
#Override
public void run() {
int index = 0;
while (!isStopped() && index < 1000) {
try {
Thread.sleep(25);
} catch (InterruptedException ex) {
}
doPause();
index++;
System.out.println(index);
}
stopTask(); // Make sure the task is marked as begin stopped ;)
}
}
}
The main criteria is you will need to pool isStopped and doPause at appropriate points to ensure that they are begin implemented as required...
To coordinate them use a CyclicBarrier.
To launch them all at the same time use a CountDownLatch.
Google the two classes above for many examples and explanations.
To fully understand what is happening read the Java Concurrency In Practice book.
I believe you can accomplish this by using Object.wait and Thread.interrupt.
Object.wait blocks until notify is called. So
private boolean paused;
private Object waitObject;
...
public void run() {
for ... {
if (this.paused) { this.waitObject.wait(); }
...
public void pause() { this.paused = true; }
public void resume() { this.paused = false; this.waitObject.notify(); }
Then you can call pause to pause the thread.
Thread.interrupt can help with stopping.
private boolean paused;
...
public void run() {
for ... {
// interrupted() is different from interrupt()!
if (this.iterrupted()) { break; }
...
To stop it, you would call interrupt() from another thread.
This is the basic idea, but there's a lot of details to worry about here. For example, wait can throw an InterruptedException you'll need to handle. Also, wait is not guaranteed to return only after a notify. It can return randomly. Here is a pair of tutorials:
Wait: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Interrupt: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
Very recently I've asked this question, but wasn unable to fix this. So I have a thread hunter (2 of them actually), who "goes off to catch wild boars". He stores these boars in a container Fridge. He will continue to do so until his working hours expire. However, in case the Fridge is full he has to wait. The aim is to wait until a wild boar is removed from the fridge, but if it takes more then 5 seconds of waiting test must be terminated. So everything works except one thing. After running test and interrupting these threads, the program still continues to run. So how do I completely terminate/stop these threads?
TEST CLASS (main)
class Test {
public static void main(String[] args) {
test1();
}
public static void test1() {
Fridge fridge = new Fridge(4);
Hunter hunter1 = new Hunter("hunter1", 4, fridge);
Hunter hunter2 = new Hunter("hunter2", 7, fridge);
Thread hunterThread1 = new Thread(hunter1);
Thread hunterThread2 = new Thread(hunter2);
hunterThread1.start();
hunterThread2.start();
try { Thread.sleep(1000); } catch (InterruptedException e) {}
hunterThread1.interrupt();
hunterThread2.interrupt();
System.out.println(fridge.getSize());
System.out.println(hunter1.getWorkTime());
System.out.println(hunter2.getWorkTime());
}
}
HUNTER CLASS
class Hunter extends Worker {
private int workTime;
private Fridge fridge;
public Hunter(String name, int workTime, Fridge fridge) {
super(name);
this.workTime = workTime;
this.fridge = fridge;
}
public int getWorkTime() {
return workTime;
}
public void run() {
while (workTime > 0) {
/** Each hunt takes a random amount of time (1-50 ms) **/
try { Thread.sleep(workGen()); } catch (InterruptedException e) {}
/** Add new wild boars **/
try { fridge.add(new WildBoar()); } catch (InterruptedException e) {}
workTime--;
/** If thread is interupted break the loop **/
if( Thread.currentThread().isInterrupted()){
break;
}
}
}
}
FRIDGE CLASS
import java.util.Stack;
class Fridge extends Storage {
private Stack<WildBoar> boars;
public Fridge(int cap) {
super(cap);
boars = new Stack<WildBoar>();
}
public int getCap() {
return cap;
}
public int getSize() {
return boars.size();
}
public boolean hasFreeSpace() {
if ( boars.size() < cap )
return true;
else
return false;
}
public synchronized void add(WildBoar boar) throws InterruptedException {
/** If there's no free space available wait **/
while ( !hasFreeSpace() ) {
wait();
}
/** Once there's free space available add new item **/
boars.add(boar);
}
public synchronized WildBoar remove() {
return boars.pop();
}
}
ADDITIONAL CLASSES FOR COMPILING:
abstract class Worker implements Runnable {
private String name;
public Worker(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int workGen() {
return 1 + (int)(Math.random() * (50 - 1));
}
}
class WildBoar {
public WildBoar() {}
}
abstract class Storage {
protected int cap;
public Storage(int cap) {
this.cap = cap;
}
public int getCap() {
return cap;
}
}
After you interrupt() the thread which is currently waiting, the native wait method will actually reset the interruption flag. So when you evaluate the isInterrupted() here, it is actually reset and will appear as not interrupted.
if( Thread.currentThread().isInterrupted()){
break;
}
You will have to re-interrupt the thread after an interruption occurs during the waiting
public synchronized void add(Object boar) {
/** If there's no free space available wait **/
while (!hasFreeSpace()) {
try{
wait();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
return; //or rethrow
}
}
/** Once there's free space available add new item **/
boars.add(boar);
}
Currently, the run method in your Hunter thread is discarding interruptions:
try { fridge.add(new WildBoar()); }
catch (InterruptedException e) {}
Thus, nothing happens when you later check for interruptions
if( Thread.currentThread().isInterrupted()){
break;
}
To correct this, you need to set the thread's interrupt status:
try { fridge.add(new WildBoar()); }
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Summary - ignoring the InterruptedException resets the interrupt status. If you don't or re-throw it or break, then you will need to set the interrupt status manually.