I just write some code to test the multiple threads how to synchronize,but I cannot get my expected result.The code can start 3 threads,but only one thread to process the shared resource.what is wrong with my code.
class ThreadDemo1{
public static void main (String[] args){
MultiThread tt = new MultiThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
}
class MultiThread implements Runnable {
int tickets = 100;
Object _lock = new Object();
public void run () {
System.out.println(Thread.currentThread().getName());
synchronized(_lock) {
while (true) {
if (tickets>0) {
try {
Thread.sleep(10);
} catch (Exception e) {}
System.out.println(Thread.currentThread().getName() + " is selling "+tickets--);
}
}
}
}
}
You are sleeping while holding the lock. There is no reason to multithread if you are going to do that.
public void run () {
System.out.println(Thread.currentThread().getName());
while(tickets > 0) {
synchronized(_lock) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + " is selling " + tickets--);
}
}
try {
Thread.sleep(10);
} catch (Exception e) {
}
}
}
I'm guessing the sleep was a placeholder for your processing. If possible, you should do the check and decrement inside the synchronized block, but your lengthy processing outside it.
In order for locks and multi-threading to do anything useful for you, you must make sure that your synchronized code takes as little time as possible, since that is the code that can be run by only one thread at a time.
In your code, the only thing that wasn't effectively single-threaded was your first System.println.
FYI, with that in mind, if you could have your print statements accurate but possibly out of order, it would be even better to have:
public void run () {
System.out.println(Thread.currentThread().getName());
while(tickets > 0) {
int oldTickets = 0;
synchronized(_lock) {
if (tickets > 0) {
oldTickets = tickets--;
}
}
if(oldTickets > 0) {
System.out.println(Thread.currentThread().getName() + " is selling " + oldTickets);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}
}
[1]First, there are several bad practice/mistakes in your posted code:
(1) It's better that the Lock Object to be singleton. You can use an static field object or the Class itself(Since there is only one Class in memory)
Object _lock = new Object();
private static final Object _lock = new Object();
(2) Put the while(true) {...} out of the synchronized block. In your code, if the 1st thread obtains the Lock, it will process ALL the tickets and will not stop.
Should make every thread try to obtain the Lock in each iteration of the loop.
(3) For the Thread.sleep(10), I guess you mean the thread is doing some heavy job. But it's not a good practice to put this kind of code in synchronized block(Or another name: critical region). Because there is only one thread can access the synchronized block at one time. The behavior of you code is like a single thread program, because other threads must wait until the currently running thread finishes its job.
Pls see below code:
public class ThreadDemo1 {
public static void main(String[] args) {
MultiThread tt = new MultiThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
}
public class MultiThread implements Runnable {
private static int tickets = 100;
private static final Object _lock = new Object();
public void run() {
System.out.println(Thread.currentThread().getName());
while (tickets > 0) {
try {
synchronized (_lock) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + " is selling " + tickets--);
}
}
Thread.sleep(10);
} catch (Exception e) {
}
}
}
}
[2]Second, if you just want to synchronize the threads in picking the tickets. Try to use Atomic* Classes instead of synchronized block, it’s No-lock and will bring you a better performance. Example:
import java.util.concurrent.atomic.AtomicInteger;
public class MultiThreadAtomic implements Runnable {
private static AtomicInteger tickets = new AtomicInteger(100);
public void run() {
System.out.println(Thread.currentThread().getName());
int ticketsRemaining = 0;
while ((ticketsRemaining = tickets.getAndDecrement()) > 0) {
System.out.println(Thread.currentThread().getName() + " is selling " + ticketsRemaining);
try {
Thread.sleep(10);
}
catch(InterruptedException ie) {}
}
}
}
Related
how can I create a loop (or something else if that is a better way) where I can create some new threads.
So far I have 2 producer and consumer threads. But I would like to create, for example, 5 producers and 5 consumers, and each thread produced / consumed a different "product", two threads cannot do the same.
I'd like it to be something like this:
Produced thread0 produce 0
Consume thread0 consume 0
....
Produced thread4 produce 4
Consume thread4 consume 4
Thank you for every hint.
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ProducerConsumer {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(2);
Thread producerThread = new Thread(new Runnable() {
#Override
public void run() {
try {
int value = 0;
while (true) {
blockingQueue.put(value);
System.out.println("Produced " + value);
value++;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumerThread = new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
int value = blockingQueue.take();
System.out.println("Consume " + value);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producerThread.start();
consumerThread.start();
producerThread.join();
consumerThread.join();
}
}
Use a thread pool (Executors.newFixedThreadpool or Executors.newCachedThreadPool)
Don't forget to manage thread synchronization for resources using synchronized blocks.
Use volatile keyword for values that will be written/read simutaneously by several threads (see What is the volatile keyword useful for?)
I've used lambda syntax to redefine your runnables for clarity.
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ProducerConsumer {
private static volatile int prodValue = 0;
private static final Object valueSync = new Object();
public static void main(String[] args) throws InterruptedException {
final BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(2);
final ExecutorService threadPool = Executors.newCachedThreadPool();
final Runnable producer = () -> {
try {
while (true) {
synchronized(valueSync) {
blockingQueue.put(prodValue);
System.out.println(Thread.currentThread().getId() + " Produced " + prodValue);
prodValue++;
}
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
final Runnable consumer = () -> {
try {
while (true) {
int value = blockingQueue.take();
System.out.println(Thread.currentThread().getId() + " Consumed " + value);
Thread.sleep(1200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 5; i++) { //Create 5 threads of each
System.out.println("Loop " + i);
threadPool.execute(producer);
threadPool.execute(consumer);
Thread.sleep(500); //Wait a little
}
System.out.println("Loop done");
//Wait for all threads to complete with timeout
threadPool.awaitTermination(15, TimeUnit.SECONDS);
System.out.println("STOP !");
//Forceful shutdown of all threads (will happen as all threads are in a while(true) loop
threadPool.shutdownNow();
}
}
About synchronization: here you want your value to be added to the queue and incremented seemingly at once (atomically). synchronized around the operations prevents threads from simultaneously running this piece of code, which would result in the same value added multiple times into the queue, and then incremented multiple times (it happens if you decrease the Thread.sleep values to something close to 0 and remove the synchronized block).
I could have used blockingQueue as argument for synchronized but chose to use a dedicated object to make it more obvious.
I'm trying to implement a simple read/write lock for a resource accessed concurrently by multiple threads. The workers randomly try reading or writing to a shared object. When a read lock is set, workers should not be able to write until the lock is released. When a write lock is set, read and write are not permitted.
Although my implementation seems to work, I believe it is conceptually wrong.
A read operation taking place should allow for more read operations happening at the same time, resulting in the overall number of reads being larger than the number of writes. My program yields numbers that follow the probability of these operations being performed by a worker.
I feel like my implementation is actually not concurrent at all, but I'm having a hard time identifying the mistake. I would really appreciate being pointed in the right direction.
Main class that dispatches and terminates workers:
class Main {
private static final int THREAD_NUMBER = 4;
public static void main(String[] args) {
// creating workers
Thread[] workers = new Thread[THREAD_NUMBER];
for (int i = 0; i < THREAD_NUMBER; i++) {
workers[i] = new Thread(new Worker(i + 1));
}
System.out.println("Spawned workers: " + THREAD_NUMBER);
// starting workers
for (Thread t : workers) {
t.start();
}
try {
Thread.sleep((long) 10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// stopping workers
System.out.println("Stopping workers...");
for (Thread t : workers) {
t.interrupt();
}
}
}
The Resource class:
class Resource {
enum ResourceLock {
ON,
OFF
}
private static Resource instance = null;
private ResourceLock writeLock = ResourceLock.OFF;
private ResourceLock readLock = ResourceLock.OFF;
private Resource() {}
public static synchronized Resource getInstance() {
if (instance == null) {
instance = new Resource();
}
return instance;
}
public ResourceLock getWriteLock() {
return writeLock;
}
public ResourceLock getReadLock() {
return readLock;
}
public void setWriteLock() {
writeLock = ResourceLock.ON;
}
public void setReadLock() {
readLock = ResourceLock.ON;
}
public void releaseWriteLock() {
writeLock = ResourceLock.OFF;
}
public void releaseReadLock() {
readLock = ResourceLock.OFF;
}
}
And finally the Worker class:
import java.util.Random;
class Worker implements Runnable {
private static final double WRITE_PROB = 0.5;
private static Random rand = new Random();
private Resource res;
private int id;
public Worker(int id) {
res = Resource.getInstance();
this.id = id;
}
public void run() {
message("Started.");
while (!Thread.currentThread().isInterrupted()) {
performAction();
}
}
private void message(String msg) {
System.out.println("Worker " + id + ": " + msg);
}
private void read() {
synchronized(res) {
while (res.getWriteLock() == Resource.ResourceLock.ON) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
res.setReadLock();
// perform read
try {
Thread.sleep((long) 500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
res.releaseReadLock();
res.notifyAll();
}
message("Finished reading.");
}
private void write() {
synchronized(res) {
while (res.getWriteLock() == Resource.ResourceLock.ON || res.getReadLock() == Resource.ResourceLock.ON) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
res.setWriteLock();
// perform write
try {
Thread.sleep((long) 500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
res.releaseWriteLock();
res.notifyAll();
}
message("Finished writing.");
}
private void performAction() {
double r = rand.nextDouble();
if (r <= WRITE_PROB) {
write();
} else {
read();
}
}
}
The reasoning behind having two separate locks for read and write is that I want to have the ability to atomise both operations and their queries for the lock.
Here is an example of the output I'm getting with a 0.5 write probability:
Spawned workers: 4
Worker 2: Started.
Worker 3: Started.
Worker 1: Started.
Worker 4: Started.
Worker 2: Finished writing.
Worker 4: Finished reading.
Worker 1: Finished writing.
Worker 3: Finished writing.
Worker 1: Finished reading.
Worker 4: Finished writing.
Worker 2: Finished reading.
Worker 4: Finished reading.
Worker 1: Finished reading.
Worker 3: Finished writing.
Worker 1: Finished writing.
Worker 4: Finished writing.
Worker 2: Finished writing.
Worker 4: Finished writing.
Worker 1: Finished reading.
Worker 3: Finished writing.
Worker 1: Finished writing.
Worker 4: Finished reading.
Worker 2: Finished writing.
Stopping workers...
Worker 4: Finished writing.
Worker 1: Finished writing.
Worker 3: Finished reading.
Worker 2: Finished reading.
Help much appreciated.
You are performing the entire operation within a synchronized block, so there is no concurrency. Further, there is no precedence towards any lock kind, as at most one thread can own a lock. Not performing the entire operation in a synchronized block won’t work with your current code, as every reader does a readLock = ResourceLock.OFF at the end, regardless of how many readers are there. Without a counter, you can’t support multiple readers correctly.
Besides that, it’s a strange code structure, to provide a Resource class maintaining the state but leaving it entirely up to the callers to do the right thing with it. That’s not the way to deal with responsibility and encapsulation.
An implementation may look like
class ReadWriteLock {
static final int WRITE_LOCKED = -1, FREE = 0;
private int numberOfReaders = FREE;
private Thread currentWriteLockOwner;
public synchronized void acquireReadLock() throws InterruptedException {
while(numberOfReaders == WRITE_LOCKED) wait();
numberOfReaders++;
}
public synchronized void releaseReadLock() {
if(numberOfReaders <= 0) throw new IllegalMonitorStateException();
numberOfReaders--;
if(numberOfReaders == FREE) notifyAll();
}
public synchronized void acquireWriteLock() throws InterruptedException {
while(numberOfReaders != FREE) wait();
numberOfReaders = WRITE_LOCKED;
currentWriteLockOwner = Thread.currentThread();
}
public synchronized void releaseWriteLock() {
if(numberOfReaders!=WRITE_LOCKED || currentWriteLockOwner!=Thread.currentThread())
throw new IllegalMonitorStateException();
numberOfReaders = FREE;
currentWriteLockOwner = null;
notifyAll();
}
}
It simply uses a counter of acquired read locks, setting the counter to -1 when there is a write lock (so write locks can not be nested). Acquiring a read lock may succeed whenever there is no write lock, so there is no need to implement precedence for them, the possibility to succeed when another thread already has a real lock, is sufficient. In fact, when having a significantly larger number of readers than writers, you may encounter the “starving writer” problem.
The worker simplifies to
class Worker implements Runnable {
private static final double WRITE_PROB = 0.5;
private static final Random rand = new Random();
private final ReadWriteLock theLock;
private final int id;
public Worker(int id, ReadWriteLock lock) {
theLock = lock;
this.id = id;
}
public void run() {
message("Started.");
while(!Thread.currentThread().isInterrupted()) {
performAction();
}
}
private void message(String msg) {
System.out.println("Worker " + id + ": " + msg);
}
private void read() {
try {
theLock.acquireReadLock();
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
// perform read
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
finally { theLock.releaseReadLock(); }
message("Finished reading.");
}
private void write() {
try {
theLock.acquireWriteLock();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
// perform write
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
finally { theLock.releaseWriteLock(); }
message("Finished writing.");
}
private void performAction() {
double r = rand.nextDouble();
if (r <= WRITE_PROB) {
write();
} else {
read();
}
}
}
Note that I avoided global variables here. The lock should get passed to the constructor. It’s also important that the methods return when being interrupted during the lock acquisition. Self interrupting and retrying the acquisition like in your original code will lead to an infinite loop, as the next wait would again throw an InterruptedException after you restored the current thread’s interrupted state. Of course, proceeding without having the lock would be wrong too, so the only valid options are not restoring the interrupted state or returning immediately.
The only change to your main program is to construct a pass the lock instance:
ReadWriteLock sharedLock = new ReadWriteLock();
// creating workers
Thread[] workers = new Thread[THREAD_NUMBER];
for (int i = 0; i < THREAD_NUMBER; i++) {
workers[i] = new Thread(new Worker(i + 1, sharedLock));
}
System.out.println("Spawned workers: " + THREAD_NUMBER);
// starting workers
for (Thread t : workers) {
t.start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// stopping workers
System.out.println("Stopping workers...");
for (Thread t : workers) {
t.interrupt();
}
This is the simple implementation for ReadWriteLock with more priority given to write operation:
public class ReadWriteLock{
private int readers = 0;
private int writers = 0;
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException{
while(writers > 0 || writeRequests > 0){
wait();
}
readers++;
}
public synchronized void unlockRead(){
readers--;
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
while(readers > 0 || writers > 0){
wait();
}
writeRequests--;
writers++;
}
public synchronized void unlockWrite() throws InterruptedException{
writers--;
notifyAll();
}
}
Source: http://tutorials.jenkov.com/java-concurrency/read-write-locks.html
Hi I have been trying to solve the producer consumer problem in java without semaphores. When I use single producer and single consumer then my code is working fine. But when I add more than one consumer then it is completely messing up, all the consumer threads are going into the synchronized block. I'm not sure why this is happening. Here is my code :
Producer class:
public class Producer implements Runnable {
Object SharedObject = null;
String producerName= null;
Random rn = new Random();
public Producer(Main m, String s) {
this.SharedObject = m;
this.producerName=s;
}
public Producer(Main m) {
this.SharedObject = m;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == Main.bufferSize) {
try {
System.out.println("Producer is sleeping and waiting for notification form Consumer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount++;
System.out.println(this.producerName+" Produced the item and the item count is : " + Main.itemCount);
if (Main.itemCount == 1) {
SharedObject.notify();
System.out.println("Producer Notified the cosumer to wake up");
}
}
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Consumer Class:
public class Consumer implements Runnable {
Object SharedObject = null;
String consumerName= null;
Random rn = new Random();
public Consumer(Main m, String s) {
SharedObject = m;
this.consumerName=s;
}
Consumer c= new Consumer((Main) SharedObject,consumerName);
synchronized void consume(){
synchronized (SharedObject) {
if (Main.itemCount == 0) {
try {
System.out.println(this.consumerName+" is sleeping and waiting for notify from Producer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount--;
System.out.println(this.consumerName+" consumed 1 item and the item Count is " + Main.itemCount);
if (Main.itemCount == 4) {
SharedObject.notifyAll();
System.out.println("Consumer notified the producer to wake up");
}
}
}
public void run() {
while (true) {
c.consume();
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Main Class:
public class Main {
static int itemCount = 0;
static int bufferSize = 5;
public static void main(String[] args) {
Main m = new Main();
Thread objP = new Thread(new Producer(m, "Producer1"));
Thread objC = new Thread(new Consumer(m, "Consumer1"));
Thread objC2 = new Thread(new Consumer(m, "Consumer2"));
Thread objC3 = new Thread(new Consumer(m, "Consumer3"));
objP.start();
objC.start();
objC2.start();
objC3.start();
}
}
You are using notifyAll in the producer, which wakes up all consumer threads waiting on the monitor. If you want only one consumer to wake up, you should use notify From the API documentation:
notify()
Wakes up a single thread that is waiting on this object's monitor.
notifyAll()
Wakes up all threads that are waiting on this object's monitor.
It would also be better for your consumers to actually check that they can consume a resource when they are woken up. If you want to continue to use notifyAll, a consumer should be able to be awoken, and if insufficient resource is available, go back to waiting.
I suggest printing the main.itemCount. This will make it more obvious what the problems you have are.
You have to pay attention to when you are calling notify.
Why does your producer only call notify when there is exactly one item available? Shouldn't the producer call notify whenever there is an item available?
The consumer only tells the producer to wake up when there are 4 items (isn't this full?).
Actually changing notifyAll() to notify() kindoff worked!!! thanks for ua suggestion guys. Here is my code:
Producer class:
package com.source;
import java.util.Random;
public class Producer implements Runnable {
Object SharedObject = null;
String producerName = null;
Random rn = new Random();
public Producer(Main m, String s) {
this.SharedObject = m;
this.producerName = s;
}
public Producer(Main m) {
this.SharedObject = m;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == Main.bufferSize) {
try {
System.out
.println(this.producerName + "is sleeping and waiting for notification form Consumer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount++;
System.out.println(this.producerName + " Produced the item and the item count is : " + Main.itemCount);
if (Main.itemCount == 1) {
SharedObject.notify();
System.out.println("Producer Notified the cosumer to wake up");
}
}
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Consumer Class:
package com.source;
import java.util.Random;
public class Consumer implements Runnable {
Object SharedObject = null;
String consumerName = null;
Random rn = new Random();
public Consumer(Main m, String s) {
SharedObject = m;
this.consumerName = s;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == 0) {
try {
System.out.println(this.consumerName + " is sleeping and waiting for notify from Producer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount--;
System.out.println(this.consumerName + " consumed 1 item and the item Count is " + Main.itemCount);
if (Main.itemCount == 4) {
SharedObject.notify();
System.out.println("Consumer notified the producer to wake up");
}
}
try {
int i = rn.nextInt(1000);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Main Class:
package com.source;
public class Main {
static int itemCount = 0;
static int bufferSize = 5;
public static void main(String[] args) {
Main m = new Main();
Thread objP = new Thread(new Producer(m, "Producer1"));
Thread objC = new Thread(new Consumer(m, "Consumer1"));
Thread objC2 = new Thread(new Consumer(m, "Consumer2"));
Thread objC3 = new Thread(new Consumer(m, "Consumer3"));
Thread objP2 = new Thread(new Producer(m, "Producer2"));
Thread objP3 = new Thread(new Producer(m, "Producer3"));
objP.start();
objC.start();
objC2.start();
objC3.start();
objP2.start();
objP3.start();
}
}
Once again thanks to everyone for your valuable time and suggestions.
Sounds like you are past your initial problem but here's some more feedback.
I believe your real problem was not because of notifyAll() but because your buffer tests were if tests instead of while loops. There are classic race conditions where a thread gets awaken but there are no elements in the buffer. See my notes here. So you code should be something like:
while (Main.itemCount == Main.bufferSize) {
and
while (Main.itemCount == 0) {
Calling notifyAll() exacerbated the problem but the race conditions still exist even with just notify(). As you add more consumers or another producer you will see more problems.
Here is some other feedback.
Be very careful of locks within locks. That is a bad pattern typically and one that I use very infrequently. Do you really need consume() to be synchronized?
Object instance names should start with a lowercase letter so it should be sharedObject.
Any object that you are locking on should be private final if at all possible. You wouldn't want it changing to another object.
Using Main. anything is a bad pattern. How about creating an object with the itemCount and bufferSize and then passing the same instance of that object to all of our producer and consumers? It would also be the object you would lock on.
Be careful of sprinkling your thread code with System.out.println(...) messages as others have recommended. System.out is a synchronized class so this will add locks and memory synchronization that may move or fix the problem. Yes. Debugging threaded programs is hard.
First of all, this is not a homework.
I have written a piece of code so that:
Thread-1 prints 1,4,7,... (diff is 3)
Thread-2 prints 2,5,8,...
Thread-3 prints 3,6,9,...
And the final output should be:
1,2,3,4,5,6,7,8,9,...
Here's the code that works wonderfully well:
package threadAlgo;
public class ControlOrder {
volatile Monitor monitor = new Monitor();
public static void main(String[] args) {
ControlOrder order = new ControlOrder();
Thread one = new Thread(new Task(order.monitor, 1));
one.setName("Thread-1");
Thread two = new Thread(new Task(order.monitor, 2));
two.setName("Thread-2");
Thread three = new Thread(new Task(order.monitor, 3));
three.setName("Thread-3");
one.start();
two.start();
three.start();
}
}
class Monitor {
int threadNumber = 1;
}
class Task implements Runnable {
private Monitor monitor;
private int myThreadNumber;
private int currentCount;
Task(Monitor monitor, int myThreadNumber) {
this.monitor = monitor;
this.myThreadNumber = myThreadNumber;
this.currentCount = myThreadNumber;
}
#Override
public void run() {
while (true) {
while (monitor.threadNumber != myThreadNumber) {
synchronized (monitor) {
try {
monitor.wait(100); //DOESN'T WORK WITHOUT THE TIMEOUT!!!
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (monitor) {
if (monitor.threadNumber == myThreadNumber) {
System.out.println(Thread.currentThread().getName() + ": " + currentCount);
currentCount = currentCount + 3;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (myThreadNumber == 3) {
monitor.threadNumber = 1;
} else {
monitor.threadNumber = myThreadNumber + 1;
}
monitor.notifyAll();
}
}
}
}
The only problem is that if I use wait() instead of wait(timeout), then the thread halts.
UPDATE:
Wait condition (while loop) should be inside synchronized block. A lesson for beginners, including me.
You should always
perform notifyAll/notify in conjunction with a change in state.
check the state change before using wait() in a loop.
If you call notify() and no wait() is waiting, then the signal is lost, so unless you check a state change, (or timeout) you can block forever waiting for a signal which doesn't change.
I am trying to learn multi-threading by implementing code snippets. The problem is to distribute cards(52) among four lists using 4 threads(13 each), please suggest better solution or correction in below code.
As this is for practice on multi-threading, I have not made much stress on naming conventions and generics (apologies for this)
import java.util.LinkedList;
import java.util.List;
public class CardsDivideIntoFour {
static final int Max = 52;
static int val = 0;
static Object ox = new Object();
static List list1 = new LinkedList();
static List list2 = new LinkedList();
static List list3 = new LinkedList();
static List list4 = new LinkedList();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
while (true) {
if (val >= Max) {
break;
}
synchronized (ox) {
list1.add(++val);
System.out.println("a> " + val);
ox.notifyAll();
try {
if (val >= Max) {
// System.out.println("t1 run finished");
// Thread.currentThread().interrupt();
break;
}
Thread.sleep(1000);
ox.wait();
} catch (InterruptedException e) {
}
}
}
// Unreachable code
// System.out.println("t1 run finished");
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
while (true) {
if (val >= Max) {
break;
}
synchronized (ox) {
list2.add(++val);
System.out.println("b> " + val);
ox.notifyAll();
try {
if (val >= Max) {
break;
}
Thread.sleep(1000);
ox.wait();
} catch (InterruptedException e) {
}
}
}
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
while (true) {
if (val >= Max) {
break;
}
synchronized (ox) {
list3.add(++val);
System.out.println("c> " + val);
ox.notifyAll();
try {
if (val >= Max) {
break;
}
Thread.sleep(1000);
ox.wait();
} catch (InterruptedException e) {
}
}
}
}
});
Thread t4 = new Thread(new Runnable() {
public void run() {
while (true) {
if (val >= Max) {
break;
}
synchronized (ox) {
list4.add(++val);
System.out.println("d> " + val);
ox.notifyAll();
try {
if (val >= Max) {
break;
}
Thread.sleep(1000);
ox.wait();
} catch (InterruptedException e) {
}
}
}
}
});
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (Exception e) {
}
System.out.print("List1 has > ");
for (Object o : list1) {
System.out.print((Integer) o + ",");
}
System.out.println("");
System.out.print("List2 has > ");
for (Object o : list2) {
System.out.print((Integer) o + ",");
}
System.out.println("");
System.out.print("List3 has > ");
for (Object o : list3) {
System.out.print((Integer) o + ",");
}
System.out.println("");
System.out.print("List4 has > ");
for (Object o : list4) {
System.out.print((Integer) o + ",");
}
}
}
Why re-inventing the wheel? The new Java SE 7 provides the Fork\Join framework, which does this job for you concurrently.
What about adding a field indicating the current turn of thread?
static int turn = 0;
Take a look at the code.
Details of synchronization
There are three parts of thread synchronization.
1) First, the thread must aquire the lock at synchronized (ox). The thread is being in the blocking state, until the holder thread releases the lock, then the thread attempts to aquire the lock. If it fails again to aquire the lock, it is put again in blocking state.
2) When the thread aquire the lock and enter the block of synchronized, it must firstly determine whether it is really able to aquire the lock or wait for some operation to be done. Thus we have a loop to check if the turn is the thread's turn. If it is not, the thread puts itself in the wait state, saying "I must wait for the one that has the turn to complete its task". The thread then remains in the waiting state, until another thread awakes it with notifyAll. It then re-determine whether it is able to do the job, if not, it puts itself again in waiting state. Otherwise, it does its job.
3) At final, the thread doesn't forgest to wake up the other waiting threads using notfiyAll after finishing its task. If it forgets, the other threads will still in waiting state for ever. This state is called deadlock and may cause the program to hung up.