So hey everyone, i'm actually new with coding and had a lot of problems with it even with the basic.
So my lecturer give this case study: simulate number of plane and 4 runway that can accommodate 1 plane to landing at a time. If all 4 runway is occupied, other planes have to wait for one or more of them to take off. Its hard for me so i try with 2 runways and 4 planes first.
The Plane is thread class and Runway is normal class. What i've done so far:
Main Class
public class Main {
public static void main(String[] args) {
Runway r[] = new Runway[2];
for (int i = 0; i < r.length; i++) {
r[i] = new Runway(i);
}
Plane p[] = new Plane[4];
for (int i = 0; i < p.length; i++){
p[i] = new Plane(i, r[0], r[1]);
p[i].start();
}
}
}
Runway Class
public class Runway {
private int id;
private Lock l;
public boolean available = true;
public Runway(int id){
this.id = id;
l = new ReentrantLock();
}
public boolean landing(int idp){
boolean i;
i = l.tryLock();
if (i == true) {
available = false;
System.out.println("Plane " + idp + " is landing on Runway: " + id);
}
return i;
}
public void takeOff(int idp){
System.out.println("Plane " + idp + " is take off from Runway: " + id);
available = true;
l.unlock();
}
}
Plane Class
public class Plane extends Thread {
private Runway r1, r2;
private int id, tag;
private boolean i = false;
public Plane(int id, Runway r1, Runway r2){
this.id = id;
this.r1 = r1;
this.r2 = r2;
}
public void run(){
if (i == false) {
if (r1.available == true) {
i = r1.landing(id);
tag = 1;
} else if (r2.available == true) {
i = r2.landing(id);
tag = 2;
}
}
sleep();
if (tag == 1 & i == true){
r1.takeOff(id);
i = false;
} else if (tag == 2 & i == true) {
r2.takeOff(id);
i = false;
}
}
private void sleep(){
try {
Thread.sleep(new Random().nextInt(8)*100);
}catch (Exception e){}
}
}
This is the result...
Plane 1 is landing on Runway: 0
Plane 3 is landing on Runway: 1
Plane 1 is take off from Runway: 0
Plane 3 is take off from Runway: 1
Process finished with exit code 0
Not all planes are landed, i know this is basic but any help is appreciated :D
Here's an approach which is an alternative to synchronizing access the shared state . Marking a variable as volatile is a 'lite' alternative to synchronization that has less runtime overhead . It tells the JVM memory manager to guarantee the 'liveness' of the variable to all accessing threads
EDIT
I've made some modifications after i realised that the volatile keyword did not guarantee atomicity around the operation of attempting to land a plane.
I also realised that the ids are never modified after construction and so require no volatile keyword
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
public class Airport {
/**
* if number of planes is less than or equal to twice the number of runways
* the execution will terminate ie all planes that want to land
* will land and all those that wish to take off will take off .
* Otherwise there wont be enough runways for the landing planes and the execution will
* go on indefinitely .
*/
static Runway r[] = new Runway[10];
static Plane p[] = new Plane[20];
public static void main(String[] args) {
//instantiate array of planes
for (int i = 0; i < p.length; i++){
p[i] = new Plane(i);
}
//instantiate runways and allocate planes to runways
List<Plane> planes = Arrays.asList(p);
Iterator<Plane> iterator;
Collections.shuffle(planes);
iterator= planes.iterator();
for (int i = 0; i < r.length; i++) {
Plane p;
try {
p= iterator.next();
}catch ( RuntimeException e){
p= null;
}
r[i] = new Runway(i,p);
}
//display initial state
for (int i = 0; i < p.length; i++){
Runway runway=getUsedRunway(p[i]);
System.out.println("plane "+p[i].id + " is "+(runway==null?"waiting to land":("on runway "+runway.id)));
}
System.out.println("======== Begin! ============");
//let the games begin
for (int i = 0; i < p.length; i++){
p[i].start();
}
}
private static class Runway {
//only ever read after construction . no need for special handling for concurreny
private int id;
/**
* volatile keyword gives atomic read and atomic write operation in isolation .
* However to land the plane we need to set the runway's plane reference value based on its current value .
* This scenario is called out specifically by B Goetz in this article https://www.ibm.com/developerworks/java/library/j-jtp06197/
* ( and in his book Javas one in which volatile is insufficient for thread safety
* We need an atomic compare and set
*/
private AtomicReference<Plane> planeAtomicReference;
public Runway(int i, Plane p) {
id =i;
planeAtomicReference = new AtomicReference<>();
planeAtomicReference.set(p);
}
}
private static class Plane extends Thread {
//only ever read after construction . no need for special handling for concurreny
private int id;
Plane(int i){
id=i;
}
#Override
public void run() {
Runway runway=getUsedRunway(this);
if(runway==null){
System.out.println("plane "+id+" wants to land");
Runway availableRunway = getAvailableRunway();
while ((availableRunway=atomicallyAttempToLandPlane(this))==null) {
System.out.println("no runway available yet for plane " + id);
try {
sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("landed plane "+id+" on runway "+availableRunway.id);
}else {
System.out.println("plane "+id+" wants to take off from runway "+runway.id);
runway.planeAtomicReference.set(null);
System.out.println("plane "+id+" has taken off from runway ");
}
}
/**
*
* #param plane
* #return
*/
private Runway atomicallyAttempToLandPlane(Plane plane) {
for (int i = 0; i < r.length; i++) {
if(r[i].planeAtomicReference.compareAndSet(null,plane)){
return r[i];
}
}
return null;
}
}
/**
* does not require synchronization since the size of the arrays is fixed during execution and the elements
* to which they refer is also fixed . only the internal state of elements themselves is open to change
* and that has been guaranteed by marking it as volatile as well as additional atomic behaviour
* #return
*/
private static Runway getAvailableRunway(){
for (int i = 0; i < r.length; i++) {
if(r[i].planeAtomicReference.get() ==null){
return r[i];
}
}
return null;
}
/**
* does not require synchronization since the size of the arrays is fixed during execution and the elements
* to which they refer is also fixed . only the internal state of elements themselves is open to change
* and that has been guaranteed by marking it as volatile as well as additional atomic behaviour
* #param plane
* #return
*/
private static Runway getUsedRunway(Plane plane){
for (int i = 0; i < r.length; i++) {
final Plane planeOnRunway = r[i].planeAtomicReference.get();
if(planeOnRunway !=null && planeOnRunway.id==plane.id){
return r[i];
}
}
return null;
}
}
Approach this problem by considering the planes as threads, and number of runways as the number of locks in the semaphore.
Then the code will go something like this:
public class Runway {
Semaphore semaphore = new Semaphore(4);
public void landThePlane() {
try {
semaphore.acquire();
// code to land the plane
System.out.println("The plane is landing");
Thread.sleep(3000); // just to show you in the console that the next 4
// threads will be executed afterwards - not imp
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Runway runway = new Runway();
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(() -> runway.landThePlane());
}
}
}
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
I am trying to create a basic airport simulation using two queues. They are supposed to alternate between taking off, and when one has no more 'planes' left, the NPE needs to be handled so that the other queue can continue going until the loop has finished and both queues have run out, as one has 7 entries and the other has 4. I thought if I tried to put an exception handler in the dequeue method it might fix it, but I have to use a generic class for it, so that didn't work properly. As of right now the for loop that is meant to dequeue runs until the 4th loop, which is when it stops, throws the NPE, and exits the program. So my question is, how can I make it so that when one queue runs out, it stops trying to loop it and instead continues looping the last queue?
Here is my main class where the loop is running:
public abstract class Airport<T> {
public static void main(String[] args) {
//creates separate queues
Driver<Integer> runway1 = new Driver<>();
Driver<Integer> runway2 = new Driver<>();
//adds 7 planes into runway 1
for (int i = 0; i < 7; i++) {
runway1.enqueue(i);
}
//adds 4 planes into runway 2
for (int i = 0; i < 4; i++) {
runway2.enqueue(i);
}
int size1 = runway1.length();
int size2 = runway2.length();
//run loop while either runway has planes left
while (size1 > 0 && size2 > 0) {
System.out.println("There are currently " + size1 + " planes waiting for takeoff in Runway 1.");
System.out.println("There are currently " + size2 + " planes waiting for takeoff in Runway 2.\n");
for (int lane = 0; lane < 7; lane++) {
int lane1, lane2;
if (runway1.isEmpty()){
System.out.println("Runway 1 is empty.");
}
else {
lane1 = runway1.getFront();
System.out.println("Plane " + lane1 + " has taken off from Runway 1.");
runway1.dequeue();
}
if (runway2.isEmpty()){
System.out.println("Runway 2 is empty.");
}
else{
lane2 = runway2.getFront(); //EDIT: npe occurs here
System.out.println("Plane " + lane2 + " has taken off from Runway 2.\n");
runway2.dequeue();
}
}
}
}
}
And here is the part of my driver class:
class Driver<T> implements Queue1<T> {
private static final int defaultSize = 10;
private int maxSize; // Maximum size of queue
private int front; // Index of front element
private int rear; // Index of rear element
private T[] listArray; // Array holding queue elements
/**
* Constructors
*/
Driver() {
this(defaultSize);
}
#SuppressWarnings("unchecked")
// For generic array
Driver(int size) {
maxSize = size + 1; // One extra space is allocated
rear = 0;
front = 1;
listArray = (T[]) new Object[maxSize]; // Create listArray
}
/**
* Put "it" in queue
*/
public void enqueue(T it) {
assert ((rear + 2) % maxSize) != front : "Queue is full";
rear = (rear + 1) % maxSize; // Circular increment
listArray[rear] = it;
}
/**
* Remove and return front value
**/
public T dequeue() {
assert length() != 0 : "Queue is empty";
T it = listArray[front];
front = (front + 1) % maxSize; // Circular increment
return it;
}
/**
* Return Front Value
**/
#Override
public T getFront() {
assert length() != 0 : "Queue is empty";
return listArray[front];
}
#Override
public T getBack() {
assert length() != 0 : "Queue is empty";
return listArray[rear];
}
#Override
public boolean isEmpty() {
if(listArray == null){
return true;
}
return false;
}
/**
* #return Queue length
**/
public int length() {
return ((rear + maxSize) - front + 1) % maxSize;
}
}
I've been scratching my head over this for days, so any help would be incredibly appreciated! Thank you!
The issue is that your isEmpty() method doesn't work the way you want it to. You are using it as if it checks whether there is anything in the queue, but it is written to do something else. Assuming your length() method is correct, you need to check whether length() == 0. If it does, then you should return true. If not, you should return false.
The reason you are getting a NullPointerException is because you are assuming your list isn't empty when it is, so you try to access the next thing in your queue, which is null
In code, it would look like this:
public boolean isEmpty() {
return length()==0;
}
I don't have your driver class, so I made do with what's available:
public static void main(String [] args) {
ArrayDeque<Integer> runway1 = new ArrayDeque<>();
ArrayDeque<Integer> runway2 = new ArrayDeque<>();
//adds 7 planes into runway 1
for (int i = 0; i < 7; i++) {
runway1.offer(i);
}
//adds 4 planes into runway 2
for (int i = 0; i < 4; i++) {
runway2.offer(i);
}
//run loop while either runway has planes left
String waitingMsg = "There are currently %d planes waiting for takeoff in Runway %d.";
while (!runway1.isEmpty() && !runway2.isEmpty()) {
System.out.println(String.format(waitingMsg, runway1.size(), 1));
System.out.println(String.format(waitingMsg, runway2.size(), 2));
System.out.println();
for (int lane = 0; lane < 7; lane++) {
if (runway1.isEmpty()){
System.out.println("Runway 1 is empty.");
} else {
int lane1 = runway1.pop();
System.out.println("Plane " + lane1 + " has taken off from Runway 1.");
}
if (runway2.isEmpty()) {
System.out.println("Runway 2 is empty.");
} else{
int lane2 = runway2.pop();
System.out.println("Plane " + lane2 + " has taken off from Runway 2.\n");
}
}
}
}
I am looking for an implementation of interval lock. Given an interval (x, y), a thread can acquire the lock if no-one else is acquiring any interval that contains point p where x <= p <= y.
My current idea is maintaining an array of existing granted intervals (x1, y1, x2, y2, ..., xn, yn) where x1 < y1 < x2 < y2 < ... < xn < yn and checks to see if (x, y) overlaps with any of those intervals.
The search takes O(logn) time which makes me happy. However, when the search returns that there is some overlaps, the lock function needs to somehow retry efficiently until it can acquire the lock when others release their interval locks. Busy-waiting or sleep seems not a good idea.
Is there a way to implement the retry efficiently?
As #c0der suggested I've made an implementation that simply tracks the locked intervals.
My code implies a Range class that ...
is immutable
has a lower and upper bound (extending to unbounded ranges shouldn't be too hard)
properly implements equals() and hashCode()
The RangeLock class currently only implements a blocking lock method. Unlocking is done through a returned Unlocker instance. This is to avoid threads not having acquired the lock, being able to unlock a given Range.
public class RangeLock<T extends Comparable<? super T>> {
private final SortedSet<Range<T>> locked = new TreeSet<>(Comparator.comparing(Range::lower));
private final Object lock = new Object();
public Unlocker lock(Range<T> range) throws InterruptedException {
synchronized (lock) {
while (!available(range)) {
lock.wait();
}
locked.add(range);
return () -> {
synchronized (lock) {
locked.remove(range);
lock.notifyAll();
}
};
}
}
private boolean available(Range<T> range) {
SortedSet<Range<T>> tailSet = locked.tailSet(range);
SortedSet<Range<T>> headSet = locked.headSet(range);
return (tailSet.isEmpty() || !tailSet.first().overlaps(range)) && (headSet.isEmpty() || !headSet.last().overlaps(range));
}
public interface Unlocker {
void unlock();
}
}
I think the question is essentially about an efficient way to have a thread wait and retry.
How about listening to changes in the
array of existing granted intervals
and retry only when it has changed ?
The following should not be considered a proper implementation (my experience with thread is very limited), but a demonstration of the proposed mechanism:
Ranges.java and Range.java
//represents all ranges
//see also: https://stackoverflow.com/a/7721388/3992939
public class Ranges {
private List<Range> ranges = new ArrayList<>();
private PropertyChangeSupport rangeChangedProperty = new PropertyChangeSupport(this);
public Range getRange(int rangeStart, int rangeEnd) {
if(contains(rangeStart) || contains(rangeEnd)) {
return null;
}
Range range = new Range(rangeStart, rangeEnd);
range.addListener( (observable, oldValue, newValue) -> {
rangeChangedProperty.firePropertyChange("Range", "-" , "changed");
}
);
ranges.add(range);
return range;
}
private boolean contains(int number){
for(Range range : ranges) {
if(range.contains(number)) {return true;}
}
return false;
}
public boolean removeRange(Range range) {
boolean isContains = ranges.remove(range);
rangeChangedProperty.firePropertyChange("Range", "-" , "removed");
return isContains;
}
/**
* Listen to {#link #rangeChangedProperty}. Fires whenever a range changes
* or removed.
* <br/>A client and a listener and when it fires, notify all threads.
*/
public void addChangeListener(PropertyChangeListener listener) {
rangeChangedProperty.addPropertyChangeListener(listener);
}
//represents a single range
//It is muttable
//can be implemented using ValueRange (https://stackoverflow.com/a/40716042/3992939)
class Range{
private SimpleIntegerProperty low = new SimpleIntegerProperty();
private SimpleIntegerProperty high = new SimpleIntegerProperty();
private SimpleObjectProperty<int[]> rangeProperty = new SimpleObjectProperty<>();
private Range(int rangeStart, int rangeEnd){
low.set(rangeStart) ; high.set(rangeEnd);
updateRange();
low.addListener((observable, oldValue, newValue) -> { updateRange(); });
high.addListener((observable, oldValue, newValue) -> { updateRange(); });
}
/**
* Listen to {#link #rangeProperty} that changes whenever the range changes
*/
void addListener(ChangeListener<int[]> listener) {
rangeProperty.addListener(listener);
}
private void updateRange() {rangeProperty.set(new int[] {low.get(), high.get()});}
public int getRangeStart() { return low.get(); }
public void setRangeStart(int rangeStart) { low.set(rangeStart);}
public int getRangeEnd() {return high.get();}
public void setRangeEnd(int rangeEnd) { high.set(rangeEnd);}
public boolean contains(int number){
int min = Math.min(low.get(), high.get());
int max = Math.max(low.get(), high.get());
return ((number >= min) && (number <= max));
}
}
}
GetRange.java
//used to simulate a thread trying to get a range
public class GetRange implements Runnable{
private Ranges ranges;
private int low, high;
private String id;
GetRange(Ranges ranges, int low, int high, String id) {
this.ranges = ranges;
this.low = low; this.high = high; this.id = id;
}
#Override
public void run() {
synchronized (ranges) {
while(ranges.getRange(low,high) == null) {
System.out.println("Tread "+ id + " is waiting");
try {
ranges.wait();
} catch (InterruptedException ex) { ex.printStackTrace();}
}
}
System.out.println("Tread "+ id + " got range. All done");
}
}
Test is with :
//test
public static void main(String[] args) throws InterruptedException {
Ranges ranges = new Ranges();
ranges.addChangeListener( (evt) -> {
synchronized (ranges) {
ranges.notifyAll();
System.out.println(evt.getPropertyName() + " "+ evt.getNewValue());
}
});
Range range1 = ranges.getRange(10,15);
Range range2 = ranges.getRange(20,25);
new Thread(new GetRange(ranges, 10, 12, "A")).start();
new Thread(new GetRange(ranges, 21, 28, "B")).start();
new Thread(new GetRange(ranges, 10, 12, "C")).start();
Thread.sleep(50);
System.out.println("-- Changing end of range 1. Threads notifyied and keep waiting -----");
range1.setRangeEnd(16); //no thread effected
Thread.sleep(50);
System.out.println("-- Changing start of range 1. Threads notifyied and A or C get range -----");
range1.setRangeStart(13); //effects thread A or C
Thread.sleep(50);
System.out.println("-- Removing range 2. Threads notifyied and B get range -----");
ranges.removeRange(range2);//effects thread B
Thread.sleep(50);
System.exit(1);
}
Output:
Tread A is waiting Tread C is waiting Tread B is waiting
-- Changing end of range 1. Threads notifyied and keep waiting -----
Range changed
Tread B is waiting
Tread C is waiting
Tread A is waiting
-- Changing start of range 1. Threads notifyied and A or C get range ----- Range changed Tread A got range. All done
Thread C is waiting
Tread B is waiting
-- Removing range 2. Threads notifyied and B get range -----
Range removed
Tread B got range. All done
Tread C is waiting
Guava's Striped locks may be of interest to you.
If you have a function int key(int p) which returns the index i of the interval [x_i,y_i] which p belongs to, you could probably use a Striped lock to achieve your goal.
For instance, if we had as interval bounds the points x_1, x_2, ... x_n such that x_i < x_(i+1) and x_(i+1) - x_i remains constant over all i from 1 to n, we could use something like key(p) = p -> (p - x_1) / n.
However, based on the notation you chose, this assumption may not hold and the function key be not as straightforward - but hopefully a lock striping solution will work for you.
This is my implementation for IntervalLock that supports Read and Write locks. Reads may acquire locks that have ranges overlapped, while a write must wait if its range overlaps with any other read or write. The basic idea is to use an interval tree to store the ranges. At a given time, each range may hold a write lock or multiple read locks. Insertion and deletion ranges from the tree must done carefully to prevent any race conditions. The code uses an implementation of interval tree from here.
SemaphoreInterval.java
package intervallock;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import datastructures.Interval;
public class SemaphoreInterval implements Interval {
private ArrayList<Semaphore> semaphores;
private int start;
private int end;
private int mode;
public SemaphoreInterval(int start, int end, int mode) {
this.semaphores = new ArrayList<>(1);
this.start = start;
this.end = end;
this.mode = mode;
}
public int getMode() {
return mode;
}
public ArrayList<Semaphore> getSemaphores() {
return semaphores;
}
#Override
public int start() {
return start;
}
#Override
public int end() {
return end+1;
}
}
IntervalLock.java
package intervallock;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Semaphore;
import datastructures.IntervalTree;
/**
* An implementation of Interval Lock
*
* #author Hieu
*
*/
public class IntervalLock {
public IntervalTree<SemaphoreInterval> tree;
private Semaphore treeLock;
private int maxPermits;
public static final int READ = 0;
public static final int WRITE = 1;
public IntervalLock(int maxPermits) {
tree = new IntervalTree<>();
treeLock = new Semaphore(1);
this.maxPermits = maxPermits;
}
/**
* Acquire a lock on range [start, end] with the specified mode.
* #param start The start of the interval
* #param end The end of the interval
* #param mode The mode, either IntervalLock.READ or IntervalLock.WRITE.
* #return The SemaphoreInterval instance.
*/
public SemaphoreInterval acquire(int start, int end, int mode) {
SemaphoreInterval si = new SemaphoreInterval(start, end, mode);
Set<Semaphore> semaphores = new HashSet<>();
try {
treeLock.acquire();
} catch (InterruptedException e) {
e.printStackTrace(System.out);
System.exit(-1);
}
Iterator<SemaphoreInterval> overlappers = tree.overlappers(si);
while (overlappers.hasNext()) {
SemaphoreInterval i = overlappers.next();
if (i == null) {
System.out.println("Error: Getting a null interval");
System.exit(-1);
}
if (i.compareTo(si) == 0)
continue;
switch (i.getMode()) {
case READ:
if (mode == WRITE)
semaphores.addAll(i.getSemaphores());
break;
case WRITE:
semaphores.addAll(i.getSemaphores());
break;
}
}
SemaphoreInterval result = tree.insert(si);
if (result != null)
si = result;
si.getSemaphores().add(new Semaphore(0));
treeLock.release();
for (Semaphore s: semaphores) {
try {
s.acquire();
} catch (InterruptedException e) {
e.printStackTrace(System.out);
System.exit(-1);
}
}
return si;
}
/**
* Release the range lock hold on specified SemaphoreInterval.
* #param si The semaphore interval returned by the acquire().
*/
public void release(SemaphoreInterval si) {
try {
treeLock.acquire();
} catch (InterruptedException e) {
e.printStackTrace(System.out);
System.exit(-1);
}
if (si.getSemaphores() == null || si.getSemaphores().size() == 0) {
System.out.println("Error: Empty array of semaphores");
treeLock.release();
return;
}
Semaphore sm = si.getSemaphores().remove(0);
if (si.getSemaphores().size() == 0) {
boolean success = tree.delete(si);
if (!success) {
System.out.println("Error: Cannot remove an interval.");
treeLock.release();
return;
}
}
treeLock.release();
sm.release(maxPermits);
}
}
Usage
// init the lock with the max permits per semaphore (should be the max number of threads)
public static final IntervalLock lock = new IntervalLock(1000);
// ...
// acquire the lock on range [a, b] (inclusive), with mode (either IntervalLock.READ or IntervalLock.WRITE)
// it returns a SemaphoreInterval instance
SemaphoreInterval si = lock.acquire(a, b, mode);
// ...
// release the acquired lock
lock.release(si);
I hope this is not a repeat question, but I have looked at all the answers in other questions and none have satisfied my problem.
I have a program that has solves the Dining Philosopher's problem, and when I run the program, the threads wait until the next one is done before running another. This causes the thread's output to look like:
Philosopher 1 is EATING.
Philosopher 1 is THINKING.
Philosopher 5 is EATING.
Philosopher 5 is THINKING.
Philosopher 3 is EATING.
Philosopher 3 is THINKING.
... and so on. The expected output doesn't have an order. The threads should run concurrently. Here is my code, all of it is in here, with the interface just specifying the size of DINERS (5) and the State._______ is an enumeration with 3 states: State.HUNGRY, State.THINKING, and State.EATING.
import java.lang.Runnable;
import java.util.concurrent.locks.*;
import java.util.Random;
import java.lang.Thread;
import java.util.concurrent.TimeUnit;
/**
* This class handles the Philosophers, I hope they are hungry.
*
* #version 4-20-15
*/
public class Diner implements Runnable, PhilosopherInterface {
/** The lock used to control Thread access */
private final ReentrantLock lock;
/** The state that the Philosopher is in (ex: Eating, Thinking etc.) */
private State current;
/** The random number used to generate time sleeping */
private Random timeGenerator;
/** The maximum time a thread can sleep */
private final int maxTimeToSleep = 5000;
/** The minimum time a thread can sleep (1ms) */
private final int minTimeToSleep = 1;
private int philNum;
private int philIndex;
private Condition[] condition;
private State[] states;
public Diner(ReentrantLock lock, int philNumber, Condition[] condition, State[] states)
philNum = philNumber;
philIndex = philNum - 1;
current = states[philNumber-1];
timeGenerator = new Random();
this.lock = lock;
this.condition = condition;
this.condition[philIndex] = lock.newCondition();
this.states = states;
states[philIndex] = State.THINKING;
}
#Override
public void takeChopsticks() {
states[philIndex] = State.HUNGRY;
lock.lock();
try{
int left = philIndex-1;
int right = philIndex+1;
if(philNum == DINERS) right = 0;
if(philNum == 1) left = DINERS - 1;
test(left, philIndex, right);
if(states[philIndex] != State.EATING) {
condition[philIndex].await();
}
}catch(InterruptedException e){}
}
#Override
public void replaceChopsticks() {
try{
states[philIndex] = State.THINKING;
int left = philIndex-1;
int right = philIndex+1;
if(philNum == DINERS) right = 0;
if(philNum == 1) left = DINERS - 1;
int leftOfLeft = left-1;
int rightOfRight = right+1;
if(left == 0) leftOfLeft = DINERS-1;
test(leftOfLeft, left, philIndex);
if(right == DINERS-1) rightOfRight = 0;
test(philIndex, right, rightOfRight);
}finally{ lock.unlock(); }
//states[philIndex] = State.THINKING;
//condition[left].signal();
//condition[right].signal();
}
public void think() {
System.out.println("Philosopher " + philNum + " is " + State.THINKING + ".");
int timeToSleep = timeGenerator.nextInt(maxTimeToSleep) + minTimeToSleep;
try {
Thread.sleep(500);
}catch(InterruptedException e) {}
}
public void eat() {
System.out.println("Philosopher " + philNum + " is " + State.EATING + ".");
int timeToSleep = timeGenerator.nextInt(maxTimeToSleep) + minTimeToSleep;
try {
Thread.sleep(500);
}catch(InterruptedException e){}
}
#Override
public void run() {
while(true) {
think();
takeChopsticks();
eat();
replaceChopsticks();
}
}
public State getState() {
return current;
}
private void test(int left, int current, int right) {
if(states[left] != State.EATING && states[current] == State.HUNGRY
&& states[right] != State.EATING) {
states[current] = State.EATING;
condition[current].signal();
}
}
}
Why are the treads not running concurrently? Thanks for the help!
EDIT: To run it, there is a driver that is this:
public class Lunch {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread[] diners = new Thread[PhilosopherInterface.DINERS];
Condition[] table = new Condition[PhilosopherInterface.DINERS];
State[] states = new State[PhilosopherInterface.DINERS];
for(int i=0; i<PhilosopherInterface.DINERS; i++) {
states[i] = State.THINKING;
}
for(int i=0; i<PhilosopherInterface.DINERS; i++) {
Diner diner = new Diner(lock, i+1, table, states);
diners[i] = new Thread(diner);
diners[i].start();
}
}
}
EDIT2: Figured out the problem, Answer below.
Telling your threads to wait is not forcing them to work concurrently. If a thread needs to follow several steps before another one activates, then these methods(steps) should be synchronized.
I only locked once at the beginning of takeChopsticks() and unlocked at the end of replaceChopsticks(), forcing the thread to do everything before unlocking.
I used the lock() and unlock() methods at the start and finish of both takeChopsticks() and replaceChopsticks(), allowing it to run concurrently.
Try using an ExecutorService. Use ExecutorService.submit(Runnable)
and ExecutorService.shutdown() which will wait until all the Runnables have terminated and shutdown the ExecutorService.
I have 200 students waiting to enter a room with 200 seats (25 rows and 8 columns). The door capacity is 4 people. When a student enter the room, he chooses random seat (row and column). If the chosen seat is at 9th row or less it takes 1 second to sit, on 18th and less it takes 2 seconds, and if its from 18 to 25 it takes 3 seconds.
When any of them take a seat another person must come in the room.
The problem is that when the first 4 people enter the room they take seat one by one and not at once. How can I fix that?
For example if 2 people choose a seat at 5th row they both need to sit for 1 seconds and two new students must enter the room.
public class Student
{
int row;
int column;
volatile static int mutex;
//Generating random numbers for row and column
public Student(Seats[][] seats)
{
this.row = (int) Math.ceil(Math.random() * 25);
this.column = (int) Math.ceil(Math.random() * 8);
if (!seats[row][column].isTaken)
{
seats[row][column].isTaken = true;
} else
{
do
{
this.row = (int) Math.ceil(Math.random() * 25);
this.column = (int) Math.ceil(Math.random() * 8);
} while (!seats[row][column].isTaken);
seats[row][column].isTaken = true;
}
}
/*Check if the mutex is 4 (4 people are in the room) then wait
if someone enter the room increment mutex*/
synchronized void add() throws InterruptedException
{
while (mutex > 4)
wait();
Student.mutex++;
notifyAll();
}
/* Check if mutex is 0 (no one is in the room) then wait
if the student has sit - decrement mutex and notify*/
synchronized void takeSeat() throws InterruptedException
{
while (mutex == 0)
wait();
Student.mutex--;
notifyAll();
}
}
class Seats
{
int seat;
boolean isTaken;
public Seats(int seat)
{
this.seat = seat;
this.isTaken = false;
}
}
class StudentThread extends Thread
{
Seats[][] seats = new Seats[25][8];
StudentThread(Seats[][] seats)
{
this.seats = seats;
}
public void run()
{
try
{
Student student = new Student(seats);
synchronized (seats)
{
System.out.println("Student enter the room");
/*call the synchronized method from student
that increment the mutex*/
student.add();
if (Student.mutex == 4)
{
if (student.row <= 9)
{
sleep(1000);
student.takeSeat();
System.out.println("Student take a seat at "
+ student.row + " " + student.column);
}
if (student.row <= 18 && student.row > 9)
{
sleep(2000);
student.takeSeat();
System.out.println("Student take a seat at "
+ student.row + " " + student.column);
}
if (student.row <= 25 && student.row > 18)
{
sleep(3000);
student.takeSeat();
System.out.println("Student take a seat at "
+ student.row + " " + student.column);
}
}
}
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
class Main
{
public static void main(String[] args)
{
Seats[][] seats = new Seats[25][8];
//Initializing the seats
for (int i = 0; i < 25; i++)
for (int j = 0; j < 8; j++)
{
seats[i][j] = new Seats(i);
}
for (int i = 0; i < 200; i++)
{
StudentThread T1 = new StudentThread(seats);
T1.start();
}
}
}
Use a Semaphore, they are very practical for these kind of things.
To make the example a bit more realistic: imagine you need to do 200 HTTP get-requests, but the server will ban you if you run more than 4 requests at the same time. The example below shows how you can limit the number of requests running at the same time using a Semaphore.
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ResourceUsageLimiter {
static ExecutorService executor = Executors.newCachedThreadPool();
static int requests = 20;
static int maxRequestsConcurrent = 4;
static int maxRequestTime = 1000;
static Random randomizer = new Random();
static Semaphore openSlots = new Semaphore(maxRequestsConcurrent);
static long startTime = System.currentTimeMillis();
public static void main(String[] args) {
try {
for (int i = 0; i < requests; i++) {
openSlots.acquire();
executor.execute(new RequestRunner(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
static long time() {
return System.currentTimeMillis() - startTime;
}
static class RequestRunner implements Runnable {
int sleepTime, reqId;
public RequestRunner(int reqId) {
this.reqId = reqId;
sleepTime = randomizer.nextInt(maxRequestTime);
}
#Override
public void run() {
try {
System.out.println(time() + " " + reqId + " sleeping " + sleepTime);
Thread.sleep(sleepTime);
System.out.println(time() + " " + reqId + " sleep done");
} catch (Exception e) {
e.printStackTrace();
} finally {
openSlots.release();
}
}
}
}
Ofcourse, another way to limit the maximum number of requests running at the same time in the example is to use a thread pool with a fixed size of 4.
I'm writing a program in Java that deals with Semaphores for an assignment. I'm still new to the idea of Semaphores and concurrency.
The description of the problem is as follows:
A vector V[] of booleans. V[i] is "True"if Pi needs to use the critical section.
A vector of binary semaphores B[] to block processes from entering their critical section: B[i] will be the semaphore blocking process Pi.
A special scheduler process SCHED is used whenever a blocked process needs to be awakened to use the critical section.
SCHED is blocked by waiting on a special semaphore S
When a process Pi needs to enter the critical section, it sets V[i] to "True", signals the semaphore S and then waits on the semaphore B[i].
Whenever SCHED is unblocked, it selects the process Pi with the smallest index i for which V[i] is "True". Process Pi is then awakened by signaling B[i] and SCHED goes back to sleep by blocking on semaphore S.
When a process Pi leaves the critical section, it signals S.
This is my code:
import java.util.concurrent.Semaphore;
public class Process extends Thread {
static boolean V[];
int i;
static Semaphore B[]; //blocking semaphore
static Semaphore S;
private static int id;
static int N;
static int insist = 0;
public static void process (int i, int n) {
id = i;
N = n;
V = new boolean[N];
}
private void delay () {
try {
sleep (random(500));
}
catch (InterruptedException p) {
}
}
private static int random(int n) {
return (int) Math.round(n * Math.random() - 0.5);
}
private void entryprotocol(int i) {
V[Process.id] = true;
int turn = N;
while (V[Process.id] == true && turn == N) {
System.out.println("P" + Process.id + " is requesting critical section");
signal(S);
}
critical(Process.id);
wait(B[Process.id]);
V[Process.id] = false;
}
private void wait(Semaphore S) {
if (Process.id > 0) {
Process.id--;
} else {
//add Process.id to id.queue and block
wait(B[Process.id]);
}
}
private void signal(Semaphore S) {
if (B[Process.id] != null) {
Sched(Process.id);
} else {
Process.id++; //remove process from queue
critical(Process.id); //wakes up current process
}
}
private void critical(int i) {
System.out.println("P" + Process.id + " is in the critical section");
delay();
exitprotocol(i);
}
private void exitprotocol(int i) {
System.out.println("P" + Process.id + " is leaving the critical section");
V[id] = false;
signal(S);
}
public void Sched(int i) {
if (B[Process.id] == null) {
signal(B[Process.id]);
}
wait(S);
}
public void run() {
for (int i = 0; i < 5; i++) {
Sched(i);
entryprotocol(Process.id);
try {
wait(Process.id);
}
catch (InterruptedException p) {
}
signal(S);
}
}
public static void main (String[] args) {
int N = 5;
Process p[] = new Process[N];
for (int i = 0; i < N; i++) {
p[i] = new Process();
p[i].start();
}
}
}
I believe my logic here is correct but I'm getting a lot of errors (such as Exception in thread "Thread-1" java.lang.NullPointerException). Can any shed some light on what I'm doing wrong & provide me with some help. It's greatly appreciated!
Your NPE is probably due to the fact that you never initialize your Semaphore array - but its hard to say without a proper stack trace.
Two pieces of advice:
1) You might want to give your class variables more meaningful names than :
B
N
S
V.
Imagine walking away from this project and revisiting it in 4 months and had to read through that.
2) Figure out your class model on on a white board before writing any code. You have methods that take semaphores with the same name as some of your static fields. What are the relationships of the objects in your program? If you don't know, odds are your program doesn't know either.