My program require to print backward from 10 to 1. Each number print from
one thread. It uses one lock with multiple condition objects. But the
program cause a dead lock when I run it. This is my program.
This class working fine
import java.util.concurrent.*;
import java.util.*;
public class Backward {
public static void main(String[] args) {
BackwardThread[] threads = new BackwardThread[10];
MonitorArray monitorArray = new MonitorArray(10);
for(int i = 0; i < 10; ++i) {
threads[i] = new BackwardThread("thread" + i, i, monitorArray);
threads[i].start();
}
}
}
This class is working fine
import java.util.concurrent.*;
import java.util.*;
public class BackwardThread extends Thread {
private int id;
private MonitorArray monitorArray;
public BackwardThread(String name, int id, MonitorArray monitorArray) {
super(name);
this.id = id;
this.monitorArray = monitorArray;
}
public void run() {
monitorArray.waitTurn(id);
System.out.println("hello world thread id = " + id);
monitorArray.signalDone(id);
}
}
It seem all thread is lock forever on and conditions[id].signal() doesn't work.
import java.util.concurrent.locks.*;
import java.util.concurrent.locks.Condition;
public class MonitorArray {
private Lock lockvar;
private Condition[] conditions;
private int turn;
public MonitorArray(int num) {
this.lockvar = new ReentrantLock();
this.conditions = new Condition[num];
turn = num;
for (int i = 0; i < num; ++i) {
conditions[i] = lockvar.newCondition();
}
// TODO: need to initialize new variable here
}
public void waitTurn(int id) {
lockvar.lock();
while (id != turn) {
try {
conditions[id].await();
} catch (Exception exception) {
exception.printStackTrace();
}
}
lockvar.unlock();
}
public void signalDone(int id) {
lockvar.lock();
// TODO: Need to modify new variable here to allow one of the threads
// blocked on the while to continue
turn--;
if (id != 0) {
conditions[id].signal();
}
lockvar.unlock();
}
}
I have found the solution for this, I will give my explanation in the comment of my code
import java.util.concurrent.locks.*;
import java.util.concurrent.locks.Condition;
public class MonitorArray {
private Lock lockvar;
private Condition[] conditions;
private int turn;
public MonitorArray(int num) {
this.lockvar = new ReentrantLock();
this.conditions = new Condition[num];
/*
/ the turn value should should be num-1(9) instead of num(10)
/ because if turn = 10 so all threads will be in waiting section,
/ so there will be no thread to send the signal to wake up other threads
*/
turn = num-1;
for (int i = 0; i < num; ++i) {
conditions[i] = lockvar.newCondition();
}
}
public void waitTurn(int id) {
lockvar.lock();
while (id != turn) {
try {
conditions[id].await();
} catch (Exception exception) {
exception.printStackTrace();
}
}
lockvar.unlock();
}
public void signalDone(int id) {
lockvar.lock();
// TODO: Need to modify new variable here to allow one of the threads
// blocked on the while to continue
turn--;
if (id != 0) {
/*
/ this should be conditions[turn].signal(), not conditions[id]
/ because a thread cannot wake up themself,
/ when we use condition[turn] we are in thread 9 and we sent signal to wake up thread 8,
/ and furthermore, turn is reduced value and wake up the next smaller thread.
*/
conditions[turn].signal();
}
lockvar.unlock();
}
}
Related
I tried out multithreading for a project I'm making. in the project I need to do a certain calculation multiple times every time I call for a certain function. I tried making some testing code to understand how to do it, but I can't get it to work properly (the code seems to work perfectly when I debug it, but if I run it normally it doesn't work past the first cycle).
in the code there is an endless loop that mimics my project's calling for a function multiple times. I tried to do it so the thread runs while changeflag is true, and change the flag to false after every run of the calculation so it would stop from calculating it again and again, and after "calling" the function I change it to true back, so it would be able to calculate again.
following is my code:
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
public class Main {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Result> queue = new SynchronousQueue<>();
int loops = 0;
MyThread[] arr = new MyThread[10];
ArrayList<Result> ress = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
arr[i] = new MyThread(i, queue);
arr[i].start();
}
while (true) {
System.out.println(loops++);
while (ress.size() < arr.length){
ress.add(queue.take());
}
while (!ress.isEmpty()){
arr[ress.get(0).getSign()].setChangeflag(true);
ress.remove(0);
}
}
}
}
import java.util.Random;
import java.util.concurrent.BlockingQueue;
public class MyThread extends Thread{
private boolean changeflag = true;
private boolean runflag = true;
private int sign;
private BlockingQueue<Result> queue;
Random rnd = new Random();
public MyThread(int sign, BlockingQueue<Result> queue){
this.sign = sign;
this.queue = queue;
}
public void run(){
while (runflag){
if(changeflag){
changeflag = false;
try {
queue.put(sense());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public Result sense(){
return new Result( rnd.nextInt(10), sign);
}
public synchronized void setChangeflag(boolean changeflag) {
this.changeflag = changeflag;
}
}
public class Result {
private double res;
private int sign;
public Result(double res, int sign) {
this.res = res;
this.sign = sign;
}
public int getSign() {
return sign;
}
}
I recommend using Executors.newCachedThreadPool(). This will return an ExecutorService which you can use to queue your calculations using submit(Callable), which returns a Future on which you can block as desired. If you queue many tasks you can just keep a list of Futures as needed or a list of tasks then submit them to the ExecutorService.
Also note it's usually not recommended to extend from Thread.
Hope this helps!
The only reason I, at least, can see why you need Threads here is to do other work while waiting for the sense method to complete in the background. For example render some graphics or interact with the user.
If your main Thread is required to wait until all the sense job is complete for each request, then you don't need Threads. Just call the method sense directly in the main Thread.
On the other hand, if you need a background Thread doing the sense job while the main Thread is doing other work, then you will need two Threads: one is the main, and the other is the background-job. Then you probably need to have a producer-consumer pattern, where the producer (the main Thread) creates the requests and the consumer (the background Thread) executes the sense method. But then it seems like the roles are turned around again like you want to wait in the main Thread all the requests to complete after you submit them. If that is the case then you can start all the MyThreads and then call join on them when you are ready to wait for their results. For example:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
public class Main {
public static class Result {
private final int index;
private final Object value;
public Result(final int index,
final Object value) {
this.index = index;
this.value = value;
}
public int getIndex() {
return index;
}
public Object getValue() {
return value;
}
}
public static class MyRunnable implements Runnable {
private final int index;
private final Collection<Result> sharedResults;
public MyRunnable(final int index,
final Collection<Result> sharedResults) {
this.index = index;
this.sharedResults = Objects.requireNonNull(sharedResults);
}
#Override
public void run() {
final Result res = sense(); //Calculating outside the synchronized block.
synchronized (sharedResults) { //Synchronizing, because the actual instance of this collection might not be synchronized.
sharedResults.add(res);
}
}
private Result sense() {
return new Result(index, "Value" + index);
}
}
public static void main(final String[] args) {
final Thread[] t = new Thread[10];
final Collection<Result> sharedResults = new ArrayList<>();
for (int i = 0; i < t.length; ++i) {
t[i] = new Thread(new MyRunnable(i, sharedResults));
t[i].start();
}
for (final Thread thread: t)
try { thread.join(); } catch (final InterruptedException ix) { ix.printStackTrace(); }
sharedResults.forEach(res -> System.out.println("Result " + res.getIndex() + " with value \"" + res.getValue() + "\"."));
}
}
Another way is to use an ExecutorService like suggested by #m0skit0 and utilize the returned Future objects to wait for the results.
I have to create a hedge simulator. There is eg. 10 segments of it and each of them should have its own dedicated Thread simulating grow of the segment (each time we're about to calculate whether segment growed up, we should perform random test).
In addition there should be one additional, gardener Thread.
Gardener should cut segment of hence, when its size reaches 10 (then he cuts its size back to initial level of 1 and adds notifies it in his notes).
My attempt to make it working was like this:
public class Segment implements Runnable {
private int currentSize;
#Override
public void run() {
if(Math.random() < 0.3)
incrementSize();
}
private synchronized void incrementSize() {
currentSize++;
}
public synchronized int getCurrentSize() {
return currentSize;
}
public synchronized void setCurrentSize(int newSize) {
currentSize = newSize;
}
}
public class Gardener implements Runnable {
private int[] segmentsCutAmount = new int[10]; //Gardener notes
private Collection<Segment> segments;
public Gardener(Collection<Segment> segmentsToLookAfter) {
segments = segmentsToLookAfter;
}
#Override
public void run() {
while(true) {
//Have no idea how to deal with 10 different segments here
}
}
}
public class Main {
private Collection<Segment> segments = new ArrayList<>():
public void main(String[] args) {
Main program = new Main();
for(int i = 0; i < 10; i++)
program.addSegment();
Thread gardenerThread = new Thread(new Gardener(program.segments));
}
private void addSegment(Collection<Segment> segments) {
Segment segment = new Segment();
Thread segmentThread = new Thread(segment);
segmentThread.start();
segments.add(segment);
}
}
I am not sure what am I supposed to do, when segment reaches max height.
If there was 10 gardeners, every of them could observe one segment, but, unfortunelly, gardener is a lonely shooter - he has no family and his friends are very busy and are not willing to help him. And are you willing to help me? :D
I generally know basics of synchronization - synchronized methods/blocks, Locks, wait and notify methods, but this time I have totally no idea what to do :(
Its like horrible deadlock! Of course I am not expecting to be spoonfeeded. Any kind of hint would be very helpful as well. Thank you in advance and have a wonderful day!
About that queue. You can use the ExecutorService for that.
Letting the Hedge grow
So let's you have a hedge that can grow and be cut.
class Hedge {
private AtomicInteger height = new AtomicInteger(1);
public int grow() {
return height.incrementAndGet();
}
public int cut() {
return height.decrementAndGet();
}
}
And then you have an environment that will let the hedge grow. This will simulate the hedge sections; each environment is responsible for one of the sections only. It will also notify a Consumer<Integer> when the hedge size has gone.
class SectionGrower implements Runnable {
public static final Random RANDOM = new Random();
private final Hedge hedge;
private final Consumer<Integer> hedgeSizeListener;
public SectionGrower (Hedge h, Consumer<Integer> hl) {
hedge = h;
hedgeSizeListener = hl
}
public void run() {
while (true) { // grow forever
try {
// growing the hedge takes up to 20 seconds
Thread.sleep(RANDOM.nextInt(20)*1000);
int sectionHeight = hedge.grow();
hedgeSizeListener.accept(sectionHeight);
} catch (Exception e) {} // do something here
}
}
}
So at this point, you can do this.
ExecutorService growingExecutor = Executors.newFixedThreadPool(10);
Consumer<Integer> printer = i -> System.out.printf("hedge section has grown to %d\n", i.intValue());
for (int i = 0; i < 10; i++) {
Hedge section = new Hedge();
Environment grower = new SectionGrower(section, printer);
growingExecutor.submit(grower::run);
}
This will grow 10 hedge sections and print the current height for each as they grow.
Adding the Gardener
So now you need a Gardener that can cut the hedge.
class Gardener {
public static final Random RANDOM = new Random();
public void cutHedge(Hedge h) {
try {
// cutting the hedge takes up to 10 seconds
Thread.sleep(RANDOM.nextInt(10)*1000);
h.cut();
} catch (Exception e) {} // do something here
}
}
Now you need some construct to give him work; this is where the BlockingQueue comes in. We've already made sure the Environment can notify a Consumer<Integer> after a section has grown, so that's what we can use.
ExecutorService growingExecutor = Executors.newFixedThreadPool(10);
// so this is the queue
ExecutorService gardenerExecutor = Executors.newSingleThreadPool();
Gardener gardener = new Gardener();
for (int i = 0; i < 10; i++) {
Hedge section = new Hedge();
Consumer<Integer> cutSectionIfNeeded = i -> {
if (i > 8) { // size exceeded?
// have the gardener cut the section, ie adding item to queue
gardenerExecutor.submit(() -> gardener.cutHedge(section));
}
};
SectionGrower grower = new SectionGrower(section, cutSectionIfNeeded);
growingExecutor.submit(grower::run);
}
So I haven't actually tried this but it should work with some minor adjustments.
Note that I use the AtomicInteger in the hedge because it might grow and get cut "at the same time", because that happens in different threads.
The in following code Gardner waits for Segment to get to an arbitrary value of 9.
When Segment gets to 9, it notifies Gardner, and waits for Gardner to finish trimming:
import java.util.ArrayList;
import java.util.Collection;
public class Gardening {
public static void main(String[] args) {
Collection<Segment> segments = new ArrayList<>();
for(int i = 0; i < 2; i++) {
addSegment(segments);
}
Thread gardenerThread = new Thread(new Gardener(segments));
gardenerThread.start();
}
private static void addSegment(Collection<Segment> segments) {
Segment segment = new Segment();
Thread segmentThread = new Thread(segment);
segmentThread.start();
segments.add(segment);
}
}
class Gardener implements Runnable {
private Collection<Segment> segments;
private boolean isStop = false; //add stop flag
public Gardener(Collection<Segment> segmentsToLookAfter) {
segments = segmentsToLookAfter;
}
#Override
public void run() {
for (Segment segment : segments) {
follow(segment);
}
}
private void follow(Segment segment) {
new Thread(() -> {
Thread t = new Thread(segment);
t.start();
synchronized (segment) {
while(! isStop) {
try {
segment.wait(); //wait for segment
} catch (InterruptedException ex) { ex.printStackTrace();}
System.out.println("Trimming Segment " + segment.getId()+" size: "
+ segment.getCurrentSize() ); //add size to notes
segment.setCurrentSize(0); //trim size
segment.notify(); //notify so segment continues
}
}
}).start();
}
}
class Segment implements Runnable {
private int currentSize;
private boolean isStop = false; //add stop flag
private static int segmentIdCounter = 0;
private int segmentId = segmentIdCounter++; //add an id to identify thread
#Override
public void run() {
synchronized (this) {
while ( ! isStop ) {
if(Math.random() < 0.0000001) {
incrementSize();
}
if(getCurrentSize() >= 9) {
notify(); //notify so trimming starts
try {
wait(); //wait for gardener to finish
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
private synchronized void incrementSize() {
currentSize++;
System.out.println("Segment " + getId()+" size: "
+ getCurrentSize() );
}
public synchronized int getCurrentSize() { return currentSize; }
public synchronized void setCurrentSize(int newSize) {
currentSize = newSize;
}
public int getId() { return segmentId; }
}
The mutual waiting mechanizem can be implemented also with CountDownLatch.
Note that my experience with threads is limited. I hope other users comment and suggest improvements.
I am looking for a Java implementation of the following concurrency semantics. I want something similar to ReadWriteLock except symmetrical, i.e. both the read and write sides can be shared amongst many threads, but read excludes write and vice versa.
There are two locks, let's call them A and B.
Lock A is shared, i.e. there may be multiple threads holding it concurrently. Lock B is also shared, there may be multiple threads holding it concurrently.
If any thread holds lock A then no thread may take B – threads attempting to take B shall block until all threads holding A have released A.
If any thread holds lock B then no thread may take A – threads attempting to take A shall block until all threads holding B have released B.
Is there an existing library class that achieves this? At the moment I have approximated the desired functionality with a ReadWriteLock because fortunately the tasks done in the context of lock B are somewhat rarer. It feels like a hack though, and it could affect the performance of my program under heavy load.
Short answer:
In the standard library, there is nothing like what you need.
Long answer:
To easily implement a custom Lock you should subclass or delegate to an AbstractQueuedSynchronizer.
The following code is an example of a non-fair lock that implements what you need, including some (non exhausting) test. I called it LeftRightLock because of the binary nature of your requirements.
The concept is pretty straightforward:
AbstractQueuedSynchronizer exposes a method to atomically set the state of an int using the Compare and swap idiom ( compareAndSetState(int expect, int update) ), we can use the exposed state keep the count of the threads holding the lock, setting it to a positive value in case the Right lock is being held or a negative value in case the Left lock is being held.
Than we just make sure of the following conditions:
- you can lock Left only if the state of the internal AbstractQueuedSynchronizer is zero or negative
- you can lock Right only if the state of the internal AbstractQueuedSynchronizer is zero or positive
LeftRightLock.java
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Lock;
/**
* A binary mutex with the following properties:
*
* Exposes two different {#link Lock}s: LEFT, RIGHT.
*
* When LEFT is held other threads can acquire LEFT but thread trying to acquire RIGHT will be
* blocked. When RIGHT is held other threads can acquire RIGHT but thread trying to acquire LEFT
* will be blocked.
*/
public class LeftRightLock {
public static final int ACQUISITION_FAILED = -1;
public static final int ACQUISITION_SUCCEEDED = 1;
private final LeftRightSync sync = new LeftRightSync();
public void lockLeft() {
sync.acquireShared(LockSide.LEFT.getV());
}
public void lockRight() {
sync.acquireShared(LockSide.RIGHT.getV());
}
public void releaseLeft() {
sync.releaseShared(LockSide.LEFT.getV());
}
public void releaseRight() {
sync.releaseShared(LockSide.RIGHT.getV());
}
public boolean tryLockLeft() {
return sync.tryAcquireShared(LockSide.LEFT) == ACQUISITION_SUCCEEDED;
}
public boolean tryLockRight() {
return sync.tryAcquireShared(LockSide.RIGHT) == ACQUISITION_SUCCEEDED;
}
private enum LockSide {
LEFT(-1), NONE(0), RIGHT(1);
private final int v;
LockSide(int v) {
this.v = v;
}
public int getV() {
return v;
}
}
/**
* <p>
* Keep count the count of threads holding either the LEFT or the RIGHT lock.
* </p>
*
* <li>A state ({#link AbstractQueuedSynchronizer#getState()}) greater than 0 means one or more threads are holding RIGHT lock. </li>
* <li>A state ({#link AbstractQueuedSynchronizer#getState()}) lower than 0 means one or more threads are holding LEFT lock.</li>
* <li>A state ({#link AbstractQueuedSynchronizer#getState()}) equal to zero means no thread is holding any lock.</li>
*/
private static final class LeftRightSync extends AbstractQueuedSynchronizer {
#Override
protected int tryAcquireShared(int requiredSide) {
return (tryChangeThreadCountHoldingCurrentLock(requiredSide, ChangeType.ADD) ? ACQUISITION_SUCCEEDED : ACQUISITION_FAILED);
}
#Override
protected boolean tryReleaseShared(int requiredSide) {
return tryChangeThreadCountHoldingCurrentLock(requiredSide, ChangeType.REMOVE);
}
public boolean tryChangeThreadCountHoldingCurrentLock(int requiredSide, ChangeType changeType) {
if (requiredSide != 1 && requiredSide != -1)
throw new AssertionError("You can either lock LEFT or RIGHT (-1 or +1)");
int curState;
int newState;
do {
curState = this.getState();
if (!sameSide(curState, requiredSide)) {
return false;
}
if (changeType == ChangeType.ADD) {
newState = curState + requiredSide;
} else {
newState = curState - requiredSide;
}
//TODO: protect against int overflow (hopefully you won't have so many threads)
} while (!this.compareAndSetState(curState, newState));
return true;
}
final int tryAcquireShared(LockSide lockSide) {
return this.tryAcquireShared(lockSide.getV());
}
final boolean tryReleaseShared(LockSide lockSide) {
return this.tryReleaseShared(lockSide.getV());
}
private boolean sameSide(int curState, int requiredSide) {
return curState == 0 || sameSign(curState, requiredSide);
}
private boolean sameSign(int a, int b) {
return (a >= 0) ^ (b < 0);
}
public enum ChangeType {
ADD, REMOVE
}
}
}
LeftRightLockTest.java
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class LeftRightLockTest {
int logLineSequenceNumber = 0;
private LeftRightLock sut = new LeftRightLock();
#Test(timeout = 2000)
public void acquiringLeftLockExcludeAcquiringRightLock() throws Exception {
sut.lockLeft();
Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockRight());
assertFalse("I shouldn't be able to acquire the RIGHT lock!", task.get());
}
#Test(timeout = 2000)
public void acquiringRightLockExcludeAcquiringLeftLock() throws Exception {
sut.lockRight();
Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockLeft());
assertFalse("I shouldn't be able to acquire the LEFT lock!", task.get());
}
#Test(timeout = 2000)
public void theLockShouldBeReentrant() throws Exception {
sut.lockLeft();
assertTrue(sut.tryLockLeft());
}
#Test(timeout = 2000)
public void multipleThreadShouldBeAbleToAcquireTheSameLock_Right() throws Exception {
sut.lockRight();
Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockRight());
assertTrue(task.get());
}
#Test(timeout = 2000)
public void multipleThreadShouldBeAbleToAcquireTheSameLock_left() throws Exception {
sut.lockLeft();
Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockLeft());
assertTrue(task.get());
}
#Test(timeout = 2000)
public void shouldKeepCountOfAllTheThreadsHoldingTheSide() throws Exception {
CountDownLatch latchA = new CountDownLatch(1);
CountDownLatch latchB = new CountDownLatch(1);
Thread threadA = spawnThreadToAcquireLeftLock(latchA, sut);
Thread threadB = spawnThreadToAcquireLeftLock(latchB, sut);
System.out.println("Both threads have acquired the left lock.");
try {
latchA.countDown();
threadA.join();
boolean acqStatus = sut.tryLockRight();
System.out.println("The right lock was " + (acqStatus ? "" : "not") + " acquired");
assertFalse("There is still a thread holding the left lock. This shouldn't succeed.", acqStatus);
} finally {
latchB.countDown();
threadB.join();
}
}
#Test(timeout = 5000)
public void shouldBlockThreadsTryingToAcquireLeftIfRightIsHeld() throws Exception {
sut.lockLeft();
CountDownLatch taskStartedLatch = new CountDownLatch(1);
final Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> {
taskStartedLatch.countDown();
sut.lockRight();
return false;
});
taskStartedLatch.await();
Thread.sleep(100);
assertFalse(task.isDone());
}
#Test
public void shouldBeFreeAfterRelease() throws Exception {
sut.lockLeft();
sut.releaseLeft();
assertTrue(sut.tryLockRight());
}
#Test
public void shouldBeFreeAfterMultipleThreadsReleaseIt() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
final Thread thread1 = spawnThreadToAcquireLeftLock(latch, sut);
final Thread thread2 = spawnThreadToAcquireLeftLock(latch, sut);
latch.countDown();
thread1.join();
thread2.join();
assertTrue(sut.tryLockRight());
}
#Test(timeout = 2000)
public void lockShouldBeReleasedIfNoThreadIsHoldingIt() throws Exception {
CountDownLatch releaseLeftLatch = new CountDownLatch(1);
CountDownLatch rightLockTaskIsRunning = new CountDownLatch(1);
Thread leftLockThread1 = spawnThreadToAcquireLeftLock(releaseLeftLatch, sut);
Thread leftLockThread2 = spawnThreadToAcquireLeftLock(releaseLeftLatch, sut);
Future<Boolean> acquireRightLockTask = Executors.newSingleThreadExecutor().submit(() -> {
if (sut.tryLockRight())
throw new AssertionError("The left lock should be still held, I shouldn't be able to acquire right a this point.");
printSynchronously("Going to be blocked on right lock");
rightLockTaskIsRunning.countDown();
sut.lockRight();
printSynchronously("Lock acquired!");
return true;
});
rightLockTaskIsRunning.await();
releaseLeftLatch.countDown();
leftLockThread1.join();
leftLockThread2.join();
assertTrue(acquireRightLockTask.get());
}
private synchronized void printSynchronously(String str) {
System.out.println(logLineSequenceNumber++ + ")" + str);
System.out.flush();
}
private Thread spawnThreadToAcquireLeftLock(CountDownLatch releaseLockLatch, LeftRightLock lock) throws InterruptedException {
CountDownLatch lockAcquiredLatch = new CountDownLatch(1);
final Thread thread = spawnThreadToAcquireLeftLock(releaseLockLatch, lockAcquiredLatch, lock);
lockAcquiredLatch.await();
return thread;
}
private Thread spawnThreadToAcquireLeftLock(CountDownLatch releaseLockLatch, CountDownLatch lockAcquiredLatch, LeftRightLock lock) {
final Thread thread = new Thread(() -> {
lock.lockLeft();
printSynchronously("Thread " + Thread.currentThread() + " Acquired left lock");
try {
lockAcquiredLatch.countDown();
releaseLockLatch.await();
} catch (InterruptedException ignore) {
} finally {
lock.releaseLeft();
}
printSynchronously("Thread " + Thread.currentThread() + " RELEASED left lock");
});
thread.start();
return thread;
}
}
I don't know any library that does that you want. Even if there is such a library it possess little value because every time your request changes the library stops doing the magic.
The actual question here is "How to I implement my own lock with custom specification?"
Java provides tool for that named AbstractQueuedSynchronizer. It has extensive documentation. Apart from docs one would possibly like to look at CountDownLatch and ReentrantLock sources and use them as examples.
For your particular request see code below, but beware that it is 1) not fair 2) not tested
public class MultiReadWriteLock implements ReadWriteLock {
private final Sync sync;
private final Lock readLock;
private final Lock writeLock;
public MultiReadWriteLock() {
this.sync = new Sync();
this.readLock = new MultiLock(Sync.READ, sync);
this.writeLock = new MultiLock(Sync.WRITE, sync);
}
#Override
public Lock readLock() {
return readLock;
}
#Override
public Lock writeLock() {
return writeLock;
}
private static final class Sync extends AbstractQueuedSynchronizer {
private static final int READ = 1;
private static final int WRITE = -1;
#Override
public int tryAcquireShared(int arg) {
int state, result;
do {
state = getState();
if (state >= 0 && arg == READ) {
// new read
result = state + 1;
} else if (state <= 0 && arg == WRITE) {
// new write
result = state - 1;
} else {
// blocked
return -1;
}
} while (!compareAndSetState(state, result));
return 1;
}
#Override
protected boolean tryReleaseShared(int arg) {
int state, result;
do {
state = getState();
if (state == 0) {
return false;
}
if (state > 0 && arg == READ) {
result = state - 1;
} else if (state < 0 && arg == WRITE) {
result = state + 1;
} else {
throw new IllegalMonitorStateException();
}
} while (!compareAndSetState(state, result));
return result == 0;
}
}
private static class MultiLock implements Lock {
private final int parameter;
private final Sync sync;
public MultiLock(int parameter, Sync sync) {
this.parameter = parameter;
this.sync = sync;
}
#Override
public void lock() {
sync.acquireShared(parameter);
}
#Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(parameter);
}
#Override
public boolean tryLock() {
return sync.tryAcquireShared(parameter) > 0;
}
#Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(parameter, unit.toNanos(time));
}
#Override
public void unlock() {
sync.releaseShared(parameter);
}
#Override
public Condition newCondition() {
throw new UnsupportedOperationException(
"Conditions are unsupported as there are no exclusive access"
);
}
}
}
After my nth attempt to make a simple fair implementation, I think I understand why I could not find another library/example of the "mutual exclusive lock-pair": it requires a pretty specific user-case. As OP mentioned, you can get a long way with the ReadWriteLock and a fair lock-pair is only useful when there are many requests for a lock in quick succession (else you might as well use one normal lock).
The implementation below is more of a "permit dispenser": it is not re-entrant. It can be made re-entrant though (if not, I fear I failed to make the code simple and readable) but it requires some additional administration for various cases (e.g. one thread locking A twice, still needs to unlock A twice and the unlock-method needs to know when there are no more locks outstanding). An option to throw a deadlock error when one thread locks A and wants to lock B is probably a good idea.
The main idea is that there is an "active lock" that can only be changed by the lock-method when there are no (requests for) locks at all and can be changed by the unlock-method when the active locks outstanding reaches zero. The rest is basically keeping count of lock-requests and making threads wait until the active lock can be changed. Making threads wait involves working with InterruptedExceptions and I made a compromise there: I could not find a good solution that works well in all cases (e.g. application shutdown, one thread that gets interrupted, etc.).
I only did some basic testing (test class at the end), more validation is needed.
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
/**
* A pair of mutual exclusive read-locks: many threads can hold a lock for A or B, but never A and B.
* <br>Usage:<pre>
* PairedLock plock = new PairedLock();
* plock.lockA();
* try {
* // do stuff
* } finally {
* plock.unlockA();
* }</pre>
* This lock is not reentrant: a lock is not associated with a thread and a thread asking for the same lock
* might be blocked the second time (potentially causing a deadlock).
* <p>
* When a lock for A is active, a lock for B will wait for all locks on A to be unlocked and vice versa.
* <br>When a lock for A is active, and a lock for B is waiting, subsequent locks for A will wait
* until all (waiting) locks for B are unlocked.
* I.e. locking is fair (in FIFO order).
* <p>
* See also
* stackoverflow-java-concurrency-paired-locks-with-shared-access
*
* #author vanOekel
*
*/
public class PairedLock {
static final int MAX_LOCKS = 2;
static final int CLOSE_PERMITS = 10_000;
/** Use a fair lock to keep internal state instead of the {#code synchronized} keyword. */
final ReentrantLock state = new ReentrantLock(true);
/** Amount of threads that have locks. */
final int[] activeLocks = new int[MAX_LOCKS];
/** Amount of threads waiting to receive a lock. */
final int[] waitingLocks = new int[MAX_LOCKS];
/** Threads block on a semaphore until locks are available. */
final Semaphore[] waiters = new Semaphore[MAX_LOCKS];
int activeLock;
volatile boolean closed;
public PairedLock() {
super();
for (int i = 0; i < MAX_LOCKS; i++) {
// no need for fair semaphore: unlocks are done for all in one go.
waiters[i] = new Semaphore(0);
}
}
public void lockA() throws InterruptedException { lock(0); }
public void lockB() throws InterruptedException { lock(1); }
public void lock(int lockNumber) throws InterruptedException {
if (lockNumber < 0 || lockNumber >= MAX_LOCKS) {
throw new IllegalArgumentException("Lock number must be 0 or less than " + MAX_LOCKS);
} else if (isClosed()) {
throw new IllegalStateException("Lock closed.");
}
boolean wait = false;
state.lock();
try {
if (nextLockIsWaiting()) {
wait = true;
} else if (activeLock == lockNumber) {
activeLocks[activeLock]++;
} else if (activeLock != lockNumber && activeLocks[activeLock] == 0) {
// nothing active and nobody waiting - safe to switch to another active lock
activeLock = lockNumber;
activeLocks[activeLock]++;
} else {
// with only two locks this means this is the first lock that needs an active-lock switch.
// in other words:
// activeLock != lockNumber && activeLocks[activeLock] > 0 && waitingLocks[lockNumber] == 0
wait = true;
}
if (wait) {
waitingLocks[lockNumber]++;
}
} finally {
state.unlock();
}
if (wait) {
waiters[lockNumber].acquireUninterruptibly();
// there is no easy way to bring this lock back into a valid state when waiters do no get a lock.
// so for now, use the closed state to make this lock unusable any further.
if (closed) {
throw new InterruptedException("Lock closed.");
}
}
}
protected boolean nextLockIsWaiting() {
return (waitingLocks[nextLock(activeLock)] > 0);
}
protected int nextLock(int lockNumber) {
return (lockNumber == 0 ? 1 : 0);
}
public void unlockA() { unlock(0); }
public void unlockB() { unlock(1); }
public void unlock(int lockNumber) {
// unlock is called in a finally-block and should never throw an exception.
if (lockNumber < 0 || lockNumber >= MAX_LOCKS) {
System.out.println("Cannot unlock lock number " + lockNumber);
return;
}
state.lock();
try {
if (activeLock != lockNumber) {
System.out.println("ERROR: invalid lock state: no unlocks for inactive lock expected (active: " + activeLock + ", unlock: " + lockNumber + ").");
return;
}
activeLocks[lockNumber]--;
if (activeLocks[activeLock] == 0 && nextLockIsWaiting()) {
activeLock = nextLock(lockNumber);
waiters[activeLock].release(waitingLocks[activeLock]);
activeLocks[activeLock] += waitingLocks[activeLock];
waitingLocks[activeLock] = 0;
} else if (activeLocks[lockNumber] < 0) {
System.out.println("ERROR: to many unlocks for lock number " + lockNumber);
activeLocks[lockNumber] = 0;
}
} finally {
state.unlock();
}
}
public boolean isClosed() { return closed; }
/**
* All threads waiting for a lock will be unblocked and an {#link InterruptedException} will be thrown.
* Subsequent calls to the lock-method will throw an {#link IllegalStateException}.
*/
public synchronized void close() {
if (!closed) {
closed = true;
for (int i = 0; i < MAX_LOCKS; i++) {
waiters[i].release(CLOSE_PERMITS);
}
}
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder(this.getClass().getSimpleName());
sb.append("=").append(this.hashCode());
state.lock();
try {
sb.append(", active=").append(activeLock).append(", switching=").append(nextLockIsWaiting());
sb.append(", lockA=").append(activeLocks[0]).append("/").append(waitingLocks[0]);
sb.append(", lockB=").append(activeLocks[1]).append("/").append(waitingLocks[1]);
} finally {
state.unlock();
}
return sb.toString();
}
}
The test class (YMMV - works fine on my system, but may deadlock on yours due to faster or slower starting and running of threads):
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PairedLockTest {
private static final Logger log = LoggerFactory.getLogger(PairedLockTest.class);
public static final ThreadPoolExecutor tp = (ThreadPoolExecutor) Executors.newCachedThreadPool();
public static void main(String[] args) {
try {
new PairedLockTest().test();
} catch (Exception e) {
e.printStackTrace();
} finally {
tp.shutdownNow();
}
}
PairedLock mlock = new PairedLock();
public void test() throws InterruptedException {
CountDownLatch start = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(2);
mlock.lockA();
try {
logLock("la1 ");
mlock.lockA();
try {
lockAsync(start, null, done, 1);
await(start);
logLock("la2 ");
} finally {
mlock.unlockA();
}
lockAsync(null, null, done, 0);
} finally {
mlock.unlockA();
}
await(done);
logLock();
}
void lockAsync(CountDownLatch start, CountDownLatch locked, CountDownLatch unlocked, int lockNumber) {
tp.execute(() -> {
countDown(start);
await(start);
//log.info("Locking async " + lockNumber);
try {
mlock.lock(lockNumber);
try {
countDown(locked);
logLock("async " + lockNumber + " ");
} finally {
mlock.unlock(lockNumber);
//log.info("Unlocked async " + lockNumber);
//logLock("async " + lockNumber + " ");
}
countDown(unlocked);
} catch (InterruptedException ie) {
log.warn(ie.toString());
}
});
}
void logLock() {
logLock("");
}
void logLock(String msg) {
log.info(msg + mlock.toString());
}
static void countDown(CountDownLatch l) {
if (l != null) {
l.countDown();
}
}
static void await(CountDownLatch l) {
if (l == null) {
return;
}
try {
l.await();
} catch (InterruptedException e) {
log.error(e.toString(), e.getCause());
}
}
}
How about
class ABSync {
private int aHolders;
private int bHolders;
public synchronized void lockA() throws InterruptedException {
while (bHolders > 0) {
wait();
}
aHolders++;
}
public synchronized void lockB() throws InterruptedException {
while (aHolders > 0) {
wait();
}
bHolders++;
}
public synchronized void unlockA() {
aHolders = Math.max(0, aHolders - 1);
if (aHolders == 0) {
notifyAll();
}
}
public synchronized void unlockB() {
bHolders = Math.max(0, bHolders - 1);
if (bHolders == 0) {
notifyAll();
}
}
}
Update: As for "fairness" (or, rather, non-starvation), OPs requirements don't mention it. In order to implement OPs requirements + some form of fairness/non-starvation, it should be specified explicitly (what do you consider fair, how should it behave when flows of requests for currently dominant and non-dominant locks come in etc). One of the ways to implement it would be:
class ABMoreFairSync {
private Lock lock = new ReentrantLock(true);
public final Part A, B;
public ABMoreFairSync() {
A = new Part();
B = new Part();
A.other = B;
B.other = A;
}
private class Part {
private Condition canGo = lock.newCondition();
private int currentGeneration, lastGeneration;
private int holders;
private Part other;
public void lock() throws InterruptedException {
lock.lockInterruptibly();
try {
int myGeneration = lastGeneration;
if (other.holders > 0 || currentGeneration < myGeneration) {
if (other.currentGeneration == other.lastGeneration) {
other.lastGeneration++;
}
while (other.holders > 0 || currentGeneration < myGeneration) {
canGo.await();
}
}
holders++;
} finally {
lock.unlock();
}
}
public void unlock() throws InterruptedException {
lock.lockInterruptibly();
try {
holders = Math.max(0, holders - 1);
if (holders == 0) {
currentGeneration++;
other.canGo.signalAll();
}
} finally {
lock.unlock();
}
}
}
}
To be used as in:
sync.A.lock();
try {
...
} finally {
sync.A.unlock();
}
The idea of generations here is taken from "Java Concurrency in Practice", Listing 14.9.
this is an exercise where i have 1 Producer and N Consumer ( fill and remove Water into an WaterTank ) which i implemented in the shown code.
Now the text of the exercise says:
Filling an additional tank:
This way u can be sure that water won't be put in and taken away at the same time.
Or you could as well say that water can only be taken away if there is a putOperation.
I don't understand it. I have synchronized on an private final object so the first part ( won't be put and taken away at the same time ) doesn't happen anyway. Also there is no need for an additional Watertank that way.
The second part where it will be taken at the same time it will be put i also quite don't understand. Do i need Semaphores or Reeantrantlock or anything?
I know i have to put an WaterTank Object into my already existing WaterTank as far as i understand.
Thy for any help :)
public class WaterTank {
private final int capacity;
private int water;
private final Object synchobj = new Object();
public WaterTank(int capacit, int wate) {
this.capacity = capacit;
this.water = wate;
}
public void fillwater(int wata) {
synchronized (synchobj) {
if (water + wata > capacity) {
System.out.println("Cannot fill water!");
} else {
water = water + wata;
System.out.println("FILL::::Capacity: " + capacity + " and Water: " + water);
}
}
}
public void removewater(int wata) {
synchronized (synchobj) {
if (water - wata < 0) {
System.out.println("Cannot take water!");
} else {
water = water - wata;
System.out.println("REMOVE:::Capacity: " + capacity + " and Water: " + water);
}
}
}
}
public class Producer implements Runnable {
private final WaterTank T;
public Producer(WaterTank t) {
this.T = t;
}
#Override
public void run() {
while (true) {
T.fillwater(10);
}
}
}
public class Consumer implements Runnable {
private final WaterTank T;
public Consumer(WaterTank t) {
this.T = t;
}
#Override
public void run() {
while (true) {
T.removewater(10);
}
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class test {
public static void main(String[] args) {
WaterTank F = new WaterTank(100, 0);
Thread Pro = new Thread(new Producer(F));
Pro.start();
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.execute(new Consumer(F));
}
}
}
Write a class named RaceHorse that extends Thread. Each RaceHorse has a name and run() method that displays the name 5000 times. Write a Java application that instantiates 2 RaceHorse objects. The last RaceHorse to finish is the loser.
This is the question.
I have written the code for the two classes two run the thread
Here are the codes:
RaceHorse
class RaceHorse extends Thread
{
public String name;
public RaceHorse(String name)
{
this.name = name;
}
public void run()
{
for(int i = 1 ; i <= 5000; i++)
{
System.out.println(i+" "+name);
}
System.out.println(name+" finished.");
}
}
Runner
class Runner{
public static void main(String args[])
{
RaceHorse obj = new RaceHorse("Lol");
RaceHorse obj2 = new RaceHorse("BOL");
Thread t = new Thread(obj);
Thread t2 = new Thread(obj2);
t.start();
t2.start();
}
}
Now my problem is I am unable to find which of the thread finishes first and which seconds, i.e. which of the horse wins and which loses.!
First off: your RaceHorse objects are themselves threads. You should be able to say obj.start(); and it'd work just as well. So remove t and t2 entirely.
Next, you'll need some way to notify the main thread about the winner.
public void run()
{
... your loop stuff ...
// this is how we're going to do the notification.
Runner.done();
}
public class Runner
{
private static RaceHorse winner = null;
synchronized static void done()
{
// Threads calling this are going to be RaceHorse objects.
// Now, if there isn't already a winner, this RaceHorse is the winner.
if (winner == null) winner = (RaceHorse) Thread.currentThread();
}
public static void main(String[] args)
{
... create the horses ...
// start the horses running
obj.start();
obj2.start();
// wait for them to finish
obj.join();
obj2.join();
System.out.println(winner.name + " wins!");
}
}
There's no doubt a better way, but one method might be to create a class (e.g. 'Trophy') that is thread safe, has a method 'getTrohpy' that only returns true on the first call, and pass a reference to an instance of Trophy to both threads.
public class StackOverflow {
public static void main(String[] args) {
RaceHorse obj = new RaceHorse("Lol");
RaceHorse obj2 = new RaceHorse("BOL");
Thread t = new Thread(obj);
Thread t2 = new Thread(obj2);
t.start();
t2.start();
}
}
class RaceHorse extends Thread
{
//public String name;
public RaceHorse(String name)
{
this.setName(name);
}
public void run()
{
for(int i = 1 ; i <= 5000; i++)
{
System.out.println(i+" "+this.getName());
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+" finished.");
}
}
As cHao pointed out, RaceHorse extends Thread but you are creating a new Thread per horse. I would solve it the opposite way, by having RaceHorse implement Runnable instead.
Secondly, the solution using a synchronized method will work, but a general rule is always look for a class in java.util.concurrent that will solve the problem first. This one can be solved using an AtomicReference to ensure that only one horse takes the trophy.
Lastly, there could be a bias in favour of horse #1, if the main thread starts the horses' threads in a fixed order (this depends on the VM and on the overhead of starting a new thread on your OS.) Consider using a signal (for example a CountDownLatch) that all horses wait for before starting.
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
public class Runner {
public static void main(String args[]) {
AtomicReference<RaceHorse> winner =
new AtomicReference<RaceHorse>();
CountDownLatch startingPistol = new CountDownLatch(1);
RaceHorse horse1 = new RaceHorse("Lol", startingPistol, winner);
RaceHorse horse2 = new RaceHorse("BOL", startingPistol, winner);
Thread thread1 = new Thread(horse1);
Thread thread2 = new Thread(horse2);
thread1.start();
thread2.start();
startingPistol.countDown();
}
}
class RaceHorse implements Runnable {
private final String name;
private final CountDownLatch startingPistol;
private final AtomicReference<RaceHorse> winner;
public RaceHorse(String name,
CountDownLatch startingPistol,
AtomicReference<RaceHorse> winner)
{
this.name = name;
this.startingPistol = startingPistol;
this.winner = winner;
}
public void run()
{
try {
startingPistol.await();
for(int i = 1 ; i <= 5000; i++)
{
System.out.println(i+" "+name);
}
boolean iWon = winner.compareAndSet(null, this);
System.out.printf("%s %s.%n", name, iWon? "won": "lost");
} catch (InterruptedException ex) {
System.out.printf("%s was assasinated before the race started.%n", name);
Thread.currentThread().interrupt();
}
}
}
I am not going to write the code for you; but you should take a look at the notify method (see here) to be used.
One approach could be: once a thread has finished it will wait() for the other thread(s) to notify (or notifyAll()).
Another, more elegant solution, would consist of using a synchronized block on a shared object; the syncrhonized(obj) statement would be at the end of the run() method. Into that statement you could put a printline or any other code you would deem useful to determine who won the race.
This will work at the end of the main :
boolean alive1 = true;
boolean alive2 = true;
while (alive1 && alive2) {
alive1 = obj.isAlive();
alive2 = obj2.isAlive();
if (!alive1 && !alive2) {
// Too close to call
}
if (!alive1) {
// obj wins,
}
if (!alive2) {
// obj2 wins,
}
}
I'm late to the party, but I found this while looking for how to process the first result from a number of running threads. I think the easiest way is to use an ArrayBlockingQueue which gives you something like this.
public class RaceHorse extends Thread {
private ArrayBlockingQueue<RaceHorse> finishedRaceHorses;
public RaceHorse(String name) {
super(name);
}
public void run() {
for (int i = 1; i <= 50; i++) {
System.out.println(i + " " + getName());
}
System.out.println(getName() + " finished.");
finishedRaceHorses.offer(this);
}
public void setFinishedRaceHorses(ArrayBlockingQueue<RaceHorse> finishedRaceHorses) {
this.finishedRaceHorses = finishedRaceHorses;
}
}
public class Race {
private final List<RaceHorse> raceHorses;
public Race(List<RaceHorse> raceHorses) {
this.raceHorses = raceHorses;
}
public RaceHorse go() throws InterruptedException {
ArrayBlockingQueue<RaceHorse> finishedRaceHorses = new ArrayBlockingQueue<RaceHorse>(raceHorses.size());
for (RaceHorse raceHorse : raceHorses) {
raceHorse.setFinishedRaceHorses(finishedRaceHorses);
raceHorse.start();
}
return finishedRaceHorses.take();
}
}
public class Runner {
public static void main(String args[])
{
RaceHorse horseOne = new RaceHorse("Lol");
RaceHorse horseTwo = new RaceHorse("BOL");
Race race = new Race(Arrays.asList(horseOne, horseTwo));
try {
RaceHorse winner = race.go();
System.out.println("The winner is " + winner.getName());
} catch (InterruptedException e) {
System.out.println("The race was interrupted, maybe by a streaker?");
}
}
}
I have tried this problem and solved it using following code. There is room for improvement but for me this code worked perfectly :
1.RacingGame.java
/
package game;
import gamingObject.Horse;
import gamingObject.Race;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class RacingGame {
/**
* #param args
*/
public static Map<Integer, List<String>> raceToWinners = new HashMap<Integer, List<String>>();
public static int currentRace = 1;
public static boolean trackComplete = false;
private static boolean newTrackBegin;
private static boolean flag = true;
private static boolean race6Begin = false;
private static boolean race7Begin = false;
private static Object mutex = new Object();
private int frstHorseInNextRace = 0;
public static void main(String[] args) throws InterruptedException {
ExecutorService exeService = Executors.newFixedThreadPool(5);
/*
* Logic to conduct first 5 races (total horses/total track) so here
* total horses = 25 and tracks = 5 hence initial and compolsuary races
*/
RacingGame rg = new RacingGame();
for (int race = 1; race <= 5; race++) {
trackComplete = false;
currentRace = race;
while (!trackComplete) {
rg.startTrack();
}
}
/*
* Before 6th Race lets have right candidate for 6th race
*/
List<String> horseNames = chooseHorsesForRace6();
/*
* Race among 5 tops horses from 5 races
*/
currentRace++;
synchronized (mutex) {
while (!race6Begin) {
race(horseNames);
}
}
/*
* Choose candidates for last race 7
*/
horseNames = chooseHorsesForRace7();
currentRace++;
synchronized (mutex) {
while (!race7Begin) {
race(horseNames);
}
}
printResults();
System.exit(0);
}
private static void printResults() {
// TODO Auto-generated method stub
Iterator<Integer> iter = raceToWinners.keySet().iterator();
while (iter.hasNext()) {
int raceNum = iter.next();
StringBuffer sb = new StringBuffer();
System.out.println("Race" + raceNum + " : ");
List<String> horses = raceToWinners.get(raceNum);
for (int i = 0; i < 3; i++) {
sb.append(horses.get(i));
if (i < 2)
sb.append(",");
}
System.out.print(sb.toString());
System.out.println();
}
}
private static List<String> chooseHorsesForRace7() {
/*
* Adding First horse at first rank among 25 horses
*/
List<String> winners = new ArrayList<String>();
winners.add(raceToWinners.get(6).get(0));
raceToWinners.put(7, winners);
/*
* Taking first horses from races 2 and 3
*/
List<String> finalTrackHorses = new ArrayList<String>();
finalTrackHorses.add(raceToWinners.get(6).get(1));// firstHorse
finalTrackHorses.add(raceToWinners.get(6).get(2));// secondHorse
/*
* Rejecting all horses from race track whose first horses are at 4th
* and 5th rank of race 6
*/
for (int i = 1; i <= 5; i++) {
if (raceToWinners.get(i).contains(winners.get(0))) {
finalTrackHorses.add(raceToWinners.get(i).get(1));// thirdHorse
finalTrackHorses.add(raceToWinners.get(i).get(2));// forth horse
} else if (raceToWinners.get(i).contains(finalTrackHorses.get(1))) {
finalTrackHorses.add(raceToWinners.get(i).get(1));// fifth horse
}
}
return finalTrackHorses;
}
private static void race(List<String> horseNames) throws InterruptedException {
if (currentRace == 6)
race6Begin = true;
else
race7Begin = true;
newTrackBegin = true;
flag = true;
trackComplete = false;
while (flag) {
if (!trackComplete) {
/*
* Create thread for each horse
*
* Here taking slot of 5 horses and keep them running in a
* single loop.
*/
if (newTrackBegin) {
List<String> horses = Arrays.asList(horseNames.get(0),
horseNames.get(1), horseNames.get(2),
horseNames.get(3), horseNames.get(4));
Race r = new Race(horses);
r.start();
}
newTrackBegin = false;
mutex.wait(1);
} else if (trackComplete) {
mutex.notify();
flag = false;
}
}
}
private static List<String> chooseHorsesForRace6() {
List<String> lstHorses = new ArrayList<String>();
for (int i = 1; i <= 5; i++) {
/*
* Take only 1st Position Holders of first 5 races
*/
lstHorses.add(raceToWinners.get(i).get(0));
}
return lstHorses;
}
public Map<Integer, List<String>> getRaceToWinners() {
return raceToWinners;
}
public static synchronized void addTrackWinnerInList(String horseName) {
List<String> horses = raceToWinners.get(currentRace);
if (horses == null) {
List<String> raceHorses = new ArrayList<String>();
raceHorses.add(horseName);
raceToWinners.put(currentRace, raceHorses);
} else {
horses.add(horseName);
raceToWinners.put(currentRace, horses);
}
if (raceToWinners.get(currentRace) != null
&& raceToWinners.get(currentRace).size() == 5) {
trackComplete = true;
}
}
public static boolean isTrackComplete(){
return trackComplete;
}
public void startTrack() throws InterruptedException {
// TODO Auto-generated method stub
synchronized (mutex) {
flag = true;
newTrackBegin = true;
trackComplete = false;
while (!trackComplete) {
/*
* Create thread for each horse
*
* Here taking slot of 5 horses and keep them running in a
* single loop.
*/
if (newTrackBegin) {
List<String> horses = Arrays.asList("Horse"
+ (++frstHorseInNextRace), "Horse"
+ (++frstHorseInNextRace), "Horse"
+ (++frstHorseInNextRace), "Horse"
+ (++frstHorseInNextRace), "Horse"
+ (++frstHorseInNextRace));
Race r = new Race(horses);
r.start();
}
newTrackBegin = false;
}
}
}
}
2.Horse.java
package gamingObject;
import game.RacingGame;
public class Horse extends Thread{
String horseName;
public Horse(String horseName){
this.horseName = horseName;
}
#Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
RacingGame.addTrackWinnerInList(this.horseName);
}
}
3.Race.java
package gamingObject;
import game.RacingGame;
import java.util.List;
public class Race extends Thread {
List<String> horses;
private boolean flag = true;
private Object obj = new Object();
public Race(List<String> horses) {
this.horses = horses;
}
public void startRace() {
synchronized (obj) {
run();
}
}
#Override
public void run() {
synchronized (obj) {
boolean newTrackBegin = true;
while (!RacingGame.isTrackComplete()) {
/*
* Create thread for each horse
*
* Here taking slot of 5 horses and keep them running in a
* single loop.
*/
if (newTrackBegin) {
Horse h1 = new Horse(horses.get(0));
Horse h2 = new Horse(horses.get(1));
Horse h3 = new Horse(horses.get(2));
Horse h4 = new Horse(horses.get(3));
Horse h5 = new Horse(horses.get(4));
Thread t1 = new Thread(h1);
Thread t2 = new Thread(h2);
Thread t3 = new Thread(h3);
Thread t4 = new Thread(h4);
Thread t5 = new Thread(h5);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
newTrackBegin = false;
}else{
if(!RacingGame.isTrackComplete()){
try {
obj.wait(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
obj.notify();
}
}
}
}
}
}