I am new to java concurrency and working with locks.
I am trying to solve the dining problem and I don't have deadlocks yet only one thread gets actual runtime.
Can anyone tell me what am I doing wrong?
class Philosopher implements Runnable {
private Random numGenerator = new Random();
private int id;
private ChineseStick minChopstick;
private ChineseStick maxChopstick;
public Philosopher (int id, ChineseStick leftChopstick, ChineseStick rightChopstick) {
this.id = id;
if(leftChopstick.getNumber() > rightChopstick.getNumber()){
this.minChopstick = rightChopstick;
this.maxChopstick = leftChopstick;
}
else{
this.minChopstick = leftChopstick;
this.maxChopstick = rightChopstick;
}
}
/**
* Repeatedly think, pick up chopsticks, eat and put down chopsticks
*/
public void run() {
try {
while (true) {
pickUpLeftChopstick();
pickUpRightChopstick();
eat();
putDownChopsticks();
think();
}
} catch (InterruptedException e) {
System.out.println("Philosopher " + id + " was interrupted.\n");
}
catch(Exception e){
System.out.println("Philosopher " + id + " raised exceptions.\n");
}
}
/**
* Lets a random amount of time pass to model thinking.
* #throws InterruptedException
*/
private void think() throws InterruptedException {
System.out.println("Philosopher " + id + " is thinking.\n");
System.out.flush();
Thread.sleep (numGenerator.nextInt(10));
}
/**
* Locks the left chopstick to signify that this philosopher is holding it
* #throws InterruptedException
*/
private void pickUpLeftChopstick() throws InterruptedException {
while(!minChopstick.lock.tryLock()){
synchronized(minChopstick.lock){
minChopstick.lock.wait();
}
}
minChopstick.lock.lock();
System.out.println("Philosopher " + id + " is holding " + this.minChopstick.getNumber() + " chopstick.\n");
System.out.flush();
}
/**
* Locks the right chopstick to signify that this philosopher is holding it
* #throws InterruptedException
*/
private void pickUpRightChopstick() throws InterruptedException {
while(!maxChopstick.lock.tryLock()){
synchronized(maxChopstick.lock){
maxChopstick.lock.wait();
}
}
maxChopstick.lock.lock();
System.out.println("Philosopher " + id + " is holding " + this.maxChopstick.getNumber() + " chopstick.\n");
System.out.flush();
}
/**
* Lets a random amount of time pass to model eating.
* #throws InterruptedException
*/
private void eat() throws InterruptedException {
System.out.println("Philosopher " + id + " is eating.\n");
System.out.flush();
Thread.sleep (numGenerator.nextInt(10));
}
/**
* Releases the locks on both chopsticks to model putting them down so the
* other philosophers can use them.
*/
private void putDownChopsticks() {
minChopstick.lock.unlock();
synchronized(minChopstick.lock){
minChopstick.lock.notifyAll();
}
maxChopstick.lock.unlock();
synchronized(maxChopstick.lock){
maxChopstick.lock.notifyAll();
}
}
}
The stick class:
public class ChineseStick {
public ChineseStick(int number){
this.lock = new ReentrantLock();
this.number = number;
}
public Lock lock;
private int number;
public int getNumber(){
return this.number;
}
}
The Main is very simple:
public static void main (String[] args) {
// Model each chopstick with a lock
//Lock[] chopsticks = new ReentrantLock[NUM_PHILOSOPHERS];
ChineseStick[] sticks = new ChineseStick[NUM_PHILOSOPHERS];
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
sticks[i] = new ChineseStick(i);
}
// Create the philosophers and start each running in its own thread.
Philosopher[] philosophers = new Philosopher[NUM_PHILOSOPHERS];
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
philosophers[i] = new Philosopher(i, sticks[i], sticks[(i+1)%NUM_PHILOSOPHERS]);
new Thread(philosophers[i]).start();
}
}
You are trying to get the lock inside this loop: while(!maxChopstick.lock.tryLock()) …
This loop ends when tryLock returns true which implies that you have the lock. But you invoke lock additionally after the loop thus have locked twice. So a single unlock invocation does not release the lock then.
But your code contains other problems as well. You are swapping the left and right sticks in the Philosopher’s constructor based on the stick numbers which makes no sense as the main method already provides the stick instances correctly for a round table. It is correct for the last person to have a left item with a higher number than the right item as you wrap-around the array combining the last item with the first one. Swapping them then breaks what was initially correct.
Once you have fixed that, you will have the same problem as explained in this answer: If all eaters grab the left stick first, you can reach the situation that all eaters have locked their left stick and no one can proceed.
Additional coding style odds: you have a ChineseStick class but instead of providing a grab operation there, you implement it in the Philosopher with duplicate code for left and right sticks. If ChineseStick had a single pickUp() method, the Philosopher needed only invoke minChopstick.pickUp() and maxChopstick.pickUp() respectively rather than implementing two pickUp…Chopstick() methods containing the same code.
And you are mixing up Lock and synchronized. This is a perfect way to create unmaintainable, confusing code.
Related
My logic to solve this puzzle is just to make left and right chopstick free, then philosopher can grab and eat. And I don't write a condition to break the while loop because I assume those philosophers eat and think 24/7/.
Is my solution deadlock free now? Feel free to give me advice. I am quite new to multithreading
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;
public class Main {
static int philosopher = 5;
static philosopher philosophers[] = new philosopher[philosopher];
static chopstick chopsticks[] = new chopstick[philosopher];
static class chopstick {
public Semaphore mutex = new Semaphore(1);
public synchronized void grab() {
try {
mutex.acquire();
}
catch (Exception e) {
e.printStackTrace(System.out);
}
}
void release() {
mutex.release();
}
boolean isFree() {
return mutex.availablePermits() > 0;
}
}
static class philosopher extends Thread {
public int number;
public chopstick leftchopstick;
public chopstick rightchopstick;
philosopher(int num, chopstick left, chopstick right) {
number = num;
leftchopstick = left;
rightchopstick = right;
}
public synchronized void run(){
// Program wil run forever since I did not write exit statement.
// Only grab when left and right chopsticks are free
while (true) {
if(leftchopstick.isFree() & rightchopstick.isFree() ) {
leftchopstick.grab();
rightchopstick.grab();
System.out.println("philosopher " + (number+1) + " grabs left chopstick.");
System.out.println("philosopher " + (number+1) + " grabs right chopstick.");
eat();
leftchopstick.release();
System.out.println("philosopher " + (number+1) + " releases left chopstick.");
rightchopstick.release();
System.out.println("philosopher " + (number+1) + " releases right chopstick.");
}
}
}
void eat() {
try {
int sleepTime = ( 1000);
System.out.println("philosopher " + (number+1) + " eats for " + sleepTime + "miliseconds");
Thread.sleep(sleepTime);
}
catch (Exception e) {
e.printStackTrace(System.out);
}
}
}
public static void main(String argv[]) {
for (int i = 0; i < philosopher; i++) {
chopsticks[i] = new chopstick();
}
for (int i = 0; i < 5; i++) {
philosophers[i] = new philosopher(i, chopsticks[i], chopsticks[(i + 1) % philosopher]);
philosophers[i].start();
}
while (true) {
try {
// sleep 1 sec
Thread.sleep(1000);
// check for deadlock
boolean deadlock = true;
for (chopstick f : chopsticks) {
if (f.isFree()) {
deadlock = false;
break;
}
}
if (deadlock) {
System.out.println("Dead lock occurs cause Everyone grab left chopstick at the same time");
break;
}
}
catch (Exception e) {
e.printStackTrace(System.out);
}
}
System.out.println("Exit The Program!");
System.exit(0);
}
}
Here is one way that your program, in theory, could deadlock:
All the chopsticks are free,
All of the philosophers simultaneously look at the chopsticks, and see that they are free (leftchopstick.isFree() && rightchopstick.isFree()),
All of the philosophers simultaneously grab their left chopstick,
Each of them now is stuck, waiting for his neighbor to the right to put down his their right (the neighbor's left) chopstick.
Problem 2: The condition that no chopstick is free is insufficient to prove a deadlock. Two philosophers could be eating at the same time (i.e., four chopsticks in-use) while a third philosopher is holding the fifth chopstick in his left hand, waiting for the right-hand neighbor to put chopsticks down. None of the five chopsticks is free in that case, but the two philosophers who are eating eventually will finish, and put their chopsticks down, and the program will continue to run...
...Or, at least, it would have done if your main thread had not declared a deadlock, and aborted the program.
Both of the problems that I've highlighted here have the same root: You appear to believe that the testing and acquiring of chopsticks happens _atomically.
if(leftchopstick.isFree() & rightchopstick.isFree() ) {
leftchopstick.grab();
rightchopstick.grab();
...
}
That is to say, You seem to think that no other philosopher can act while one philosopher is looking at chopsticks and picking them up. But that isn't true: After philosopher P has seen that their left chopstick is free, the neighbor to the left could pick it up while P is looking to the right. After P has decided that both are free, the left neighbor still could win the race to pick up the left chopstick, and even if leftchopstick.grab() succeeds, the neigbor to the right still could win the race to grab the other one.
I'm reading the book Core java by Cay S. Horstmann. I'm confused with this code in the section concurrency.
We construct a new thread and pass our Runnable task to it, I understand up until this. The part that confuses me is that, we call the start() method to these new threads on after another. My question is that when does the first call to the start() method returns to main() method. Is it after the new thread has finished its task or does it returns while that new thread is running the task?
import java.util.Arrays;
public class Main{
public static final int DELAY = 10;
public static final int STEPS = 100;
public static final double MAX_AMOUNT = 1000;
public static void main(String[] args) {
var bank = new Bank(4, 100000);
Runnable task1 = () -> {
try {
for (int i = 0; i < STEPS; i++){
double amount = MAX_AMOUNT * Math.random();
bank.transfer(0, 1, amount);
Thread.sleep((int) (DELAY * Math.random()));
}
}catch (InterruptedException e) {
}
};
Runnable task2 = () ->{
try{
for (int i = 0; i < STEPS; i++){
double amount = MAX_AMOUNT * Math.random();
bank.transfer(2, 3, amount);
Thread.sleep((int) (DELAY * Math.random()));
}
}
catch (InterruptedException e){
}
};
new Thread(task1).start();
new Thread(task2).start();
}
}
class Bank{
private final double[] accounts;
/**
* Constructs the bank.
* #param n the number of accounts
* #param initialBalance the initial balance for each account
*
**/
public Bank(int n, double initialBalance){
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
}
/**
* Transfers money from one account to another.
* #param from the account to transfer from
* #param to the account to transfer to 27
* #param amount the amount to transfer 28
**/
public void transfer(int from, int to, double amount){
if (accounts[from] < amount) return;
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
}
/**
* Gets the sum of all account balances.
* #return the total balance 42
**/
public double getTotalBalance(){
double sum = 0;
for (double a : accounts)
sum += a;
return sum;
}
/**
* Gets the number of accounts in the bank.
* * #return the number of accounts 56
**/
public int size(){
return accounts.length;
}
}
The start method returns immediately & the Main Thread continues running.
You can see this happening with this little Proggy:
import java.time.Duration;
import java.time.ZonedDateTime;
public class Runner {
public static void main(final String[] args) throws Exception {
final Runnable runner = () -> {
System.out.println(ZonedDateTime.now() + " " + Thread.currentThread().getName() + " Running...");
sleep(Duration.ofSeconds(9));
System.out.println(ZonedDateTime.now() + " " + Thread.currentThread().getName() + " Done.");
};
System .out.println(ZonedDateTime.now() + " " + Thread.currentThread().getName() + " starting Thread 1...");
new Thread(runner).start();
System .out.println(ZonedDateTime.now() + " " + Thread.currentThread().getName() + " starting Thread 2...");
new Thread(runner).start();
sleep(Duration.ofSeconds(3));
System .out.println(ZonedDateTime.now() + " " + Thread.currentThread().getName() + " done.");
}
private static void sleep(final Duration duration) {
try {
Thread.sleep(duration.toMillis());
}
catch (final InterruptedException e) {}
}
}
Start method finish immediately after creating new thread. The result of start method is two threads that are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).
The start() method internally calls the run() method of Runnable interface to execute the code specified in the run() method in a separate thread.
Execution of starting thread in main thread is like any other statement. If you want to wait for the thread to finish you must use join method on it:
Thread t1 = new Thread(task1).start();
t1.join();
Thread ends its execution when its run method finish.
Yes it returns when the moment it handles the new run method to the new thread.
Then the thread pooling handles the control flow of the threads. Refer to threads and concurrency in java
I am writing Java program which allows me to get the geometric center of random-generated 2-dimensional points. I want the calculations to be done by custom number of threads. I want to suspend/continue calculations at any time. Unfortunately, my code doesn't work, It seems like run() is never executed. Here is what I got:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("running... " + Thread.currentThread().getName());
PointInterface p = pg.getPoint(); // getting random point(x,y)
pointCount++;
int[] pos = p.getPositions(); // getting (x,y)
System.out.println(pos[0] + ", " + pos[1] + " k");
sumxy[0] += pos[0];
sumxy[1] += pos[1];
geometricCenter[0] = (double) sumxy[0] / pointCount;
geometricCenter[1] = (double) sumxy[1] / pointCount;
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("exception caught in run()");
return;
}
}
}
Setting number of threads:
public void setNumberOfThreads(int threads) {
threadsList.clear();
for (int i = 0; i < threads; i++) {
threadsList.add(new Thread());
}
}
Starting the calculations:
public void start() {
try {
for (Thread t : threadsList) {
t.start();
}
} catch (Exception e) {
System.out.println("start() exception caught");
}
}
Suspending calculations:
public void suspendCalculations() {
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
System.out.println("SuspendCalculations() exception caught");
}
}
Resuming calculations:
I don't exactly know what I'm supposed to do here. Should I create new set of Threads like that?
public void continueCalculations() {
int x = threadsList.size();
threadsList.clear();
for (int i = 0; i < x; i++) {
threadsList.add(new Thread());
threadsList.get(i).start();
}
}
How I run my program:
public static void main(String[] args) {
ParallelCalculations pc = new ParallelCalculations(); // My main class object where run() and all the methods above are declared
PointGenerator g = new PointGenerator(); // class that allows me to generate points
PointInterface a = g.getPoint(); // getting random point
pc.setNumberOfThreads(3);
pc.setPointGenerator(g);
pc.start();
pc.suspendCalculations();
System.out.println(pc.getGeometricCenter()[0] + ", " + pc.getGeometricCenter()[1]);
pc.continueCalculations();
pc.suspendCalculations();
System.out.println(pc.getGeometricCenter()[0] + ", " + pc.getGeometricCenter()[1]);
}
If needed:
Point:
class Point {
public static final int MAX_POSITION = 16;
private int[] positions = new int[2];
Point(int _x, int _y) {
this.positions[0] = _x;
this.positions[1] = _y;
}
public int[] getPositions() {
return positions;
}
}
Point Generator:
class PointGenerator {
private int x = (int) (Math.random() * (Point.MAX_POSITION + 1));
private int y = (int) (Math.random() * (Point.MAX_POSITION + 1));
public PointInterface getPoint() { // Can be called by many Threads at the same time.
return new Point(x, y);
}
}
Your run() should be executed and should do it's thing.
Though there is a far bigger cause for random behaviour in this code: All the threads write to sumxy, geometricCenter and pointCount at he same time without any syncronisation-locks, causing more or less random behaviour. You at least need to implement some kind of synchronisation to prevent simultanious writes.
Maybe start here (Java synchonized tutorial by Oracle) if you have no clue.
But simply adding synchronisation to everything will probably just make it slower than a single thread, you will need some kind of buffer for each thread to work independently and than collect the results when they are suspended.
And now general problems:
A) Your suspendCalculations() doesn't do anything (for 1200ms to be percise). To break the calcualtion you would need to interrupt all the worker-threads since they terminate upon interruption. Call threadsList.get(i).Interrupt() to do so.
B) If you want to to be able to change the number of threads while suspended, this is a way to go. If this is not necessarry, it would be more efficient to create a constant
public static final Object LOCK = new Object();
make all the threads LOCK.wait() on that object, so resuming them is just a call to LOCK.notifyAll().
C) Instead of using your own implementaion of Point you can use java.awt.Point.
D) Returning the coordinates of a point simply in an array is really bad for readability of your code, java.awt.Point has getX() and getY() functions.
I'm trying to get into the nitty gritty of understanding how wait and notifyAll work and have hit a roadblock.
This program downloads a long text document, starts multiple threads to count characters and then outputs the count totals.
I'm using wait and notifyAll to control the thread execution so that they are completed in alphabetical order. Here's the code. I'll follow with an explanation of the problem.
public class Test {
public static void main(String[] args) {
//code that reads in the data
LongTask a = new LongTask(buffer, 'a', "Thread_a", 0);
a.start();
LongTask b = new LongTask(buffer, 'b', "Thread_b", 1);
b.start();
//Repeat code for all other characters
a.join();
System.out.println("Alphabet count is: " + SharedResults.getResults());
LongTask class contains constructor and run()
public class LongTask extends Thread {
//Instance variables created here
//LongTask constructor
public LongTask (StringBuffer buffer, char target, String name, int turn)
{
super(name);
this.sharedData = sharedData;
inputData = buffer;
this.target = target;
this.turn = turn;
}
//Run method iterates through input data and counts matching characters,
//then calls addToResults
public synchronized void run()
{
//Thread t = Thread.currentThread();
String name = this.getName();
int runTurn = this.turn;
System.out.println(name + " running - Turn " + runTurn);
Integer count = 0;
for (int i = 0; i < inputData.length(); i++) {
if (inputData.charAt(i) == target) {
count ++;
}
}
ResultsEntry newResult = new ResultsEntry(count, target);
SharedResults.addToResults(newResult, turn);
}
}
SharedResults class adds results to Array. addToResults method performs this action and controls the synchronization.
public class SharedResults extends Thread{
//Code that creates array
//Code for SharedResults constructor
public synchronized static void addToResults(ResultsEntry newResult, int turn)
{
Integer resultsCount = newResult.getCount();
char resultsTarget = newResult.getTarget();
Thread t = Thread.currentThread();
/*
* Turn number is compared to the size of the results array to control the
* order of execution.
*/
while (turn != results.size()){
try {
System.out.println("Wait printout");
t.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(t.getName() + " is adding " + newResult);
SharedResults input = new SharedResults(resultsCount, resultsTarget);
System.out.println("Cumulative Results are " + results);
t.notifyAll();
}
Here's what I'm seeing when I watch this step through in Debug.
-Input executes and all LongTask threads start
(Thread_a should be the first thread to execute addToResults)
-Some threads (not Thread_a) hit the while evaluation of addToResults and do not proceed
-Thread_a hits the while evaluation and fully executes. (Now it should be Thread_b's turn)
-Thread_e executes the "Wait printout" (just a debugging feature that tells me when a thread is waiting) and then the program hangs.
It looks to me like I haven't set up wait correctly. The program actually worked (or appeared to be) correctly until I added in the sysout. Any ideas what's going on here?
To answer my own question,
This was covered in this thread.
The problem is that notifyAll() notify all of that object's threads that are waiting. Because I was calling wait() on each thread, the notifyAll() from another thread wasn't notifying any of the other threads.
As suggested by the linked post, I created a static synchronized object and called the wait and notify methods on that object. The resulting code looked like this:
private static final Object LOCK = new Object();
public static void addToResults(ResultsEntry newResult, int turn)
{
Integer resultsCount = newResult.getCount();
char resultsTarget = newResult.getTarget();
Thread thread = Thread.currentThread();
/*
* Turn number is compared to the size of the results array to control the
* order of execution.
*/
synchronized (LOCK){
while (turn != results.size()){
try {
System.out.println(thread.getName() + " is waiting");
LOCK.wait();
} catch (InterruptedException e) {}
}
System.out.println(thread.getName() + " is adding " + newResult);
SharedResults input = new SharedResults(resultsCount, resultsTarget);
System.out.println("Cumulative Results are " + results);
LOCK.notifyAll();
}
}
Thanks to all who commented!
I am trying to make program which simulates a waitingline and lift, and individual skiers.
Now my output is fine and as expected until the skiers hit the top of the lift then begin to ski, which is when the threads begin.
My problem is, once a skier is finished he should then pend himself back into the waiting line, but alot of the skiers go missing, and never return to the line.
Any ideas?
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ThreadsAssignment {
// Declare and initalise queues and arrays
public static BlockingQueue<String> liftQueue = new LinkedBlockingQueue<String>(11);
public static BlockingQueue<String> waitQueue = new LinkedBlockingQueue<String>();
public static String toLift;
public static String toWait;
public static String liftFront = "EMPTY";
public static String waitFront;
public static int populatedLift = 0;
public static int pauseLift;
public static int slopeTime;
public static String toPend;
public static int queueSize;
public static void main(String[] args) throws Exception{
// fill both queues list for startup
for(int i = 0; i < 30; i++){
waitQueue.add(Integer.toString(i));
}
for(int j = 0; j < 10; j++){
liftQueue.add("EMPTY");
}
// loop the simulation
while(true){
System.out.println("In Queue " + "(" + waitQueue.size() + "): " + waitQueue);
System.out.println("On Lift " + "(" + populatedLift + "): " + liftQueue + "\n");
// Stop lift for 1 second
try{
Thread.sleep(1000);}
catch (InterruptedException ex) {}
// test if the lift stops
if ((Math.random() * 100) >= 95) {
Random rand = new Random();
pauseLift = rand.nextInt(8001);
System.out.println("Lift paused for " + pauseLift + " milliseconds");
try{Thread.sleep(pauseLift);}
catch (InterruptedException ex){}}
else{}
// get the head of the waiting line then add it to lift, check if any skier is waiting.
liftFront = liftQueue.peek();
if (waitQueue.size() == 0){
liftQueue.add("EMPTY");
}
else{
toLift = waitQueue.take();
liftQueue.add(toLift);
populatedLift++;
}
// if the front of the liftQueue is occupied, call a new skier thread
if (liftFront.equals("EMPTY")){
liftQueue.poll();}
else{
liftQueue.poll();
populatedLift--;
skier s = new skier(liftFront, waitQueue);
new Thread(s).start();
}
}
}
// skier thread
public static class skier extends Thread {
static String name;
static BlockingQueue<String> theQueue;
// Constructor for the thread
public skier(String name, BlockingQueue<String> theQueue){
skier.name = name;
skier.theQueue = theQueue;
}
// run method that makes random skiing time then pends the skier back into the queue
#Override public void run() {
toPend = skier.name;
Random speed = new Random();
slopeTime = speed.nextInt(10001) + 2000;
try {Thread.sleep(slopeTime);}
catch (InterruptedException ex){}
currentThread.
if (waitQueue.contains(toPend)){}
else {try {
waitQueue.put(toPend);
} catch (InterruptedException e){}
System.out.println(toPend + "has been pended");}
}
}
}
Following code may cause skiers to become missing:
static String name;
static BlockingQueue<String> theQueue;
static means that all instances of skier will share last submitted name. You must make all skiers keep their names to themselves:
final String name;
final BlockingQueue<String> theQueue; // this may be left `static` since there's only one instance, but this would be unclean code.
// Or, as an option, let `skier` instances re-use outer class `queue`.
Btw, Java has convention of starting class names with upper-case letter, so it should be Skier as well.
And you don't need EMPTY constant, just call queue.isEmpty()