Dining philosophers in java using semaphores - java

I want to solve dining philosophers problem using java semaphores but I'm stuck. Highest id chopstick should be available but it seems to be always taken and i don't know why. Can anyone tell me where I made mistake?
Fork class:
class Fork {
public static Semaphore fork = new Semaphore(1);
public int id;
Fork(int id) {
this.id = id;
}
public int getId() {
return id;
}
public boolean take() {
return fork.tryAcquire();
}
public void putDown() {
fork.release();
}}
Philosopher class:
class Philosopher extends Thread {
private Fork fork_low;
private Fork fork_high;
private String name;
Philosopher(Fork fork_low, Fork fork_high, String name) {
this.fork_low = fork_low;
this.fork_high = fork_high;
this.name = name;
}
public void run() {
try {
sleep(1000);
} catch (InterruptedException ex) {
}
while (true) {
eat();
}
}
private void eat(){
if(fork_low.take()){
if(fork_high.take()){
try {
sleep(2000); // eating;
} catch (InterruptedException ex) { }
fork_high.putDown();
fork_low.putDown();
}
else{
fork_low.putDown();
}
}
}}
Main:
public static void main(String[] args) {
String[] names = {"Plato", "Aristotle", "Cicero", "Confucius", "Eratosthenes"};
Fork[] fork = new Fork[5];
Philosopher[] philosopher = new Philosopher[5];
for (int i = 0; i < fork.length; i++) {
fork[i] = new Fork(i);
}
for (int i = 0; i < philosopher.length; i++) {
if (i != philosopher.length - 1) {
philosopher[i] = new Philosopher(fork[i], fork[i+1], names[i]);
philosopher[i].start();
} else {
philosopher[i] = new Philosopher(fork[0], fork[i], names[i]);
philosopher[i].start();
}
}
}

You have a deadlock, because the Semaphore is static in the Fork class, which is equivalent to only have one fork available. It works perfectly when you make the Semaphore not static (2 random philosophers running on the same time).
You can observe your threads working in JDK's build in tool jvisualvm.

Here is the same problem solved in C language with explaination
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
//if not used then gives warning for sleep used
//semaphore are basically designed to share the resources
// here the sem_t is the data type for the semaphore
sem_t room;//counting semaphore bcoz here only one instance of room butchair has 4
sem_t spoon[5]; //this is binary semaphore since every spoon has its own instance
void * philosopher(void *);
void eat(int);
int main()
{
int i;
int a[5];
pthread_t tid[5];// threads here are refrence to philosophers or diners bcoz we will have multiple users dining
sem_init(&room,0,4);
//1.pointer to declared semaphore
//2.pshared which has 0,1 value that is if 0 ->shared between threads
// if 1 ->shared between process
//3.value with whch u initalise the semaphore
for(i=0;i<5;i++){
//5 binary semaphore each for individual spoon
sem_init(&spoon[i],0,1);
}
for(i=0;i<5;i++){
a[i]=i;//allow 5 to enter at a time and deadlock occurs so let 4 of them in
pthread_create(&tid[i],NULL,philosopher,(void*)&a[i]);
//1.thread id 2.NULL 3.function 4.what you want to pass to the new thread
//here we pass the address of philosophers number to function
}
for(i=0;i<5;i++){
pthread_join(tid[i],NULL);
}
}
void * philosopher(void * num){
int phil=*(int *)num; //cast the number passed as void to integer
//put sem_wait on both semaphore room and spoon
sem_wait(&room);//checks if resource is available,if then allocates and blocks semaphore
// room is counting semaphore so any is alocated then it decrements the count of total semaphore and
// if all are allocated then it blocks thread and places it on queue untill resource is freed
printf("\nPhilospher number %d has sat on dining table\n",phil);
sem_wait(&spoon[phil]);
sem_wait(&spoon[(phil+1)%5]);
//spoon is binary so if value of semaphore is 1 it is changed to 0 which means semaphore is allocated and cannot be used
eat(phil);
sleep(2);
printf("\nPhilosopher %d has finished eating\n",phil);
//free the semaphores so others in thread can use resources
//returns +ve value on freeing semaphore
//for binary semaphore if queue is empty then change semaphore value to 1 if not empty then remove process from queue and
// get it ready for allocation
sem_post(&spoon[(phil+1)%5]);
sem_post(&spoon[phil]);
sem_post(&room);
}
void eat(int phil){
printf("\nPhilosopher %d is eating now\n",phil);
}

Related

Problem with critical section using Retrant Lock with Condition

I have a small project to synchronize multiple (two classes: ships, cars with a few instances with shared bufor class called Harbour) threads at the same time. They will be performing certain action on it. But I can't start with that until I synchronized the threads named "cars" in the Harbour. The Harbour has limited capacity and if this capacity is reached the "car" threads should be waiting until they will get signal that there's a free space to enter. I've used Retrant Lock with Condition but it doesn't work as I think.
public class Harbour {
final Lock protectNr;
final Condition protectNrCon;
int capacity;
int nrOfCars;
public Harbour(int capacity) {
this.capacity = capacity;
this.protectNr = new ReentrantLock();
this.protectNrCon = protectNr.newCondition();
}
public void carEnterHarbour(String name) {
try {
protectNr.lock();
if (this.nrOfCars == this.capacity)
protectNrCon.await();
nrOfCars++;
System.out.println(name + " enters");
System.out.println("Number of cars:" + this.nrOfCars);
protectNr.unlock();
} catch (InterruptedException e) {
System.out.println("Error");
}
}
public void carLeavingHarbour(String name) {
try {
protectNr.lock();
this.nrOfCars--;
protectNrCon.signal();
System.out.println(name + " leaving");
System.out.println("Number of cars:" + this.nrOfCars);
} finally {
protectNr.unlock();
}
}
}
public class Car extends Thread {
Harbour harbour;
public Car(Harbour harbour, String name) {
super(name);
this.harbour = harbour;
}
public void run() {
for (int i = 0; i < 10; i++) {
harbour.carEnterHarbour(getName());
harbour.carLeavingHarbour(getName());
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
int harbourCapacity = 20;
final Harbour harbour = new Harbour(harbourCapacity);
int nrOfCars = 500;
Car[] cars = new Car[nrOfCars];
for (int i = 0; i < nrOfCars; i++)
cars[i] = new Car(harbour, "Car-" + i);
for (int i = 0; i < nrOfCars; i++)
cars[i].start();
for (int i = 0; i < nrOfCars; i++)
cars[i].join();
}
}
What I was expecting after executing this code:
Car-386 leaving
Number of cars:**19**
Car-300 enters
Number of cars:**20**
Car-300 leaving
Number of cars:**19**
What I got:
Car-386 leaving
Number of cars:**20**
Car-300 enters
Number of cars:**21**
Car-295 enters
Number of cars:**22**
I also try to change int capacity to volatile int capacity and add some busy waiting but didn't work at all.
It looks like Threads are not block on Condition and I wonder why is this happening?
The documentation for Condition warns that spurious wakeups might occur (emphasis mine):
When waiting upon a Condition, a "spurious wakeup" is permitted to occur, in general, as a concession to the underlying platform semantics. This has little practical impact on most application programs as a Condition should always be waited upon in a loop, testing the state predicate that is being waited for. An implementation is free to remove the possibility of spurious wakeups but it is recommended that applications programmers always assume that they can occur and so always wait in a loop.
Your code doesn't honor that warning.
Your carEnterHarbour() must take this possibility of spurious wakeups into account and needs
while(this.nrOfCars == this.capacity){
protectNrCon.await();
}
instead of the simple if statement.
Depending on your requirements it might be easier to use a Semaphore:
public class Harbour {
final Semaphore slots;
public Harbour(int capacity){
this.slots = new Semaphore(capacity);
}
public void carEnterHarbour(String name) {
try{
slots.acquire();
}catch (InterruptedException e){
System.out.println("Error");
}
}
public void carLeavingHarbour(String name) {
slots.release();
}
}
Note that when using a Semaphore you don't have those locks in place when entering / leaving the Harbour and therefore it is difficult to get that ordered "car entering" / "car leaving" output together with the number of currently available slots.
In the carEnterHarbour method, you are calling await() on the protectNrCon condition, which causes the current thread to wait until it is signaled. However, you are not calling signal() anywhere in the carEnterHarbour method. This means that once a thread enters the if block, it will always wait indefinitely on the condition.
You should consider calling signal() on the protectNrCon condition after you increment nrOfCars and print the message, so that other threads waiting on the condition can be unblocked.
Additionally, you should call await() in a loop to ensure that the thread waits until the condition is true, rather than waiting indefinitely. Here is an example of how you can modify the carEnterHarbour method:
public void carEnterHarbour(String name) {
try {
protectNr.lock();
while (this.nrOfCars == this.capacity) {
protectNrCon.await();
}
nrOfCars++;
System.out.println(name+" enters");
System.out.println("Number of cars:" + this.nrOfCars);
protectNrCon.signal();
} catch (InterruptedException e) {
System.out.println("Error");
} finally {
protectNr.unlock();
}
}

How to ensure execution order of threads [duplicate]

This question already has answers here:
How threads are executed in the memory?
(2 answers)
Closed 2 years ago.
This is a simplified version of the problem. Given n number of threads, each printing a constant number all the time. For example, Thread-1 should always print 1, Thread-2 should always print 2 and so on...
How to ensure, the threads are executed in order i.e. the output should be as below:
Thread-1: 1
Thread-2: 2
Thread-3: 3
.
.
.
Thread-n: n
I have a naïve solution to do it through wait()/notify() but I guess there might be a better solution than that. Perhaps, using Semaphore maybe? I don't know.
Update:
Based on the answers received, I think I was not very clear. There are some constraints:
All threads should start at once (assume we don't really have control on that)
Once all the threads start, there should be some sort of communication between the threads to execute in order.
This sequentially execution of thread can be handled beautifully using Thread.join() method. To handle it properly, you may have to create MyRunnable(or, use any name you prefer) which implements Runnable interface. Inside MyRunnable, you can inject a parent Thread, and call parent.join() at top of MyRunnable.run() method. The code is given below:
public class SequentialThreadsTest {
static class MyRunnable implements Runnable {
static int objCount; // to keep count of sequential object
private int objNum;
private Thread parent; // keep track of parent thread
MyRunnable(Thread parent) {
this.parent = parent;
this.objNum = objCount + 1;
objCount += 1;
}
#Override
public void run() {
try {
if(parent != null) {
parent.join();
}
System.out.println("Thread-" + objNum + ": " + objNum);
} catch(InterruptedException e) {
e.printStackTrace();
// do something else
} finally {
// do what you need to do when thread execution is finished
}
}
}
public static void main(String[] args) {
int n = 10;
Thread parentThread = null;
for(int i=0; i<n; i++) {
Thread thread = new Thread(new MyRunnable(parentThread));
thread.start();
parentThread = thread;
}
}
}
And the output is:
Thread-1: 1
Thread-2: 2
Thread-3: 3
Thread-4: 4
Thread-5: 5
Thread-6: 6
Thread-7: 7
Thread-8: 8
Thread-9: 9
Thread-10: 10
You haven't specified many details, but if you only want serializable thread execution you can wait for previous thread to finish and then print. Something like this:
public static void main(String[] args) {
Thread thread = null;
for (int i = 0; i < 10; i++) {
int index = i;
Thread previousThread = thread;
thread = new Thread(() -> {
if (previousThread != null) {
try {
previousThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(index);
});
thread.start();
}
}
Try making a queue - this will do exactly what you want. Simply change the value of n to however many threads you have, and add all the threads sequentially (only once). If ever you want to stop the threads from executing, all you have to do is add end to the queue. Obviously, for a larger project, you will need to modify this code a little bit (I would recommend replacing the main method with a class initializer and pass the LinkedBlockingQueue as a pre-built argument)
import java.util.concurrent.LinkedBlockingQueue;
public class HelloWorld{
private static int n = 2;
private static LinkedBlockingQueue<Thread> queue = new LinkedBlockingQueue<>(n+1);
static Thread a = new Thread(()->{
System.out.print("a");
});
static Thread b = new Thread(()->{
System.out.print("b");
});
static Thread end = new Thread(()->{
break_ = true;
});
public static final int END = 20;//this and the counter are just here so the code doesn't run forever
public static volatile int i = 0;
public static volatile boolean break_ = false;
public static void main(String []args){
queue.add(a);
queue.add(b);
//queue.add(end);
outerloop:
while(true){
Thread toBeRun = queue.poll();
try{
toBeRun.run();
queue.add(toBeRun);
i++;
if(i>=END || break_){//i>=END does not need to be here, it's just to stop it from running forever in this example
break;
}
}catch(NullPointerException e){
break;
}
}
}
}
Note: This uses java 8 lambdas. If you're using an older version of java, you will need to create the threads using the run method.

Java Concurrency and Multithreading

This is kind of a big question.
I am attempting to create an ordered multiple producer and single consumer scenario in Java. It is ordered in the sense that after producer1, only producer2 gets control of the queue, after which producer3, after which producer1 again and so on and so forth. Just to check if that will work under every scenario, I provided the three producers with three different priorities
producer1 - Thread.NORM_PRIORITY - 4
producer2 - Thread.NORM_PRIORITY + 5
producer3 - Thread.NORM_PRIORITY
Now instead of printing what is being put in the queue and what is being consumed, I'm keeping a counter to count how many times each of the producer threads are being handed control of the queue and in what order, and printing those counts in the consumer thread.
Code is provided after the outputs.
I am confused by one particular behaviour of the threads, the code posted below works as I wanted it to, but if I replace this
while(flag==false)
wait();
if(getIndex()!=next)
return;
in the put() function of q.java, with this
while(flag==false && getIndex()!=next)
wait();
The producer threads are being handed control of the queue erratically. Like with the first code snippet, I am getting the following output, for producers 1,2 and 3 respectively
125 125 125
126 125 125
126 126 125
126 126 126
Producer1 is getting control of the queue first, then 2 then 3, and then 1 again.
But with the alternate option I am getting this output
2 6 8
2 6 8
2 6 8
The same producer keeps getting control of the queue.
Shouldn't the waiting thread NOT gain control of the queue unless it's index matches with the index of the thread which is supposed to get control of the q, like if next is 2, and producer3 is handled control of the queue, shouldn't it go into wait because of the while condition, and the queue be free to be approached by some other thread again, the process repeating until producer2 gets it?
QUEUE
import java.util.*;
class q
{
private volatile int size;
private volatile int clicks[];
private volatile boolean flag;
private volatile int next;
public q(int size)
{
this.size = size;
clicks = new int[size+1];
flag = true;
next = 1;
}
private synchronized int getIndex()
{
String name = Thread.currentThread().getName();
return (int)(name.charAt(name.length()-1))-48;
}
private synchronized void show()
{
//System.out.println("Got control -> "+name+" for index "+index);
if(flag==true)
{
int index = getIndex();
/*
System.out.println("Control provided to "+index);
Scanner s = new Scanner(System.in);
System.out.println("Press enter to continue");
String c = s.next();
*/
clicks[index]+=1;
next = (index%size)+1;
//System.out.println("Provide control to "+next);
}
else
{
int i;
for(i = 1;i<=size;i++)
System.out.print(clicks[i]+" ");
System.out.println();
}
}
public synchronized void put()
{
try
{
while(flag==false)
wait();
if(getIndex()!=next)
return;
show();
flag = false;
notify();
}
catch(Exception e)
{
System.out.println("Exception caught - "+e);
}
}
public synchronized void get()
{
try
{
while(flag==true)
wait();
show();
flag = true;
notifyAll();
}
catch(Exception e)
{
System.out.println("Exception caught - "+e);
}
}
}
PRODUCER
class producer implements Runnable
{
private q queue;
public producer(q queue)
{
this.queue = queue;
}
public void run()
{
try
{
//int i;
while(true)
queue.put();
}
catch(Exception e)
{
System.out.println("Exception caught - "+e);
}
}
}
CONSUMER
class consumer implements Runnable
{
private q queue;
public consumer(q queue)
{
this.queue = queue;
}
public void run()
{
try
{
while(true)
queue.get();
}
catch(Exception e)
{
System.out.println("Exception caught - "+e);
}
}
}
TESTCLASS
class testclass
{
private q queue;
private producer p1; //lowest priority
private producer p2; //highest priority
private producer p3; //normal priority
private consumer c;
private Thread pt1;
private Thread pt2;
private Thread pt3;
private Thread ct;
public testclass()
{
queue = new q(3);
p1 = new producer(queue);
p2 = new producer(queue);
p3 = new producer(queue);
c = new consumer(queue);
pt1 = new Thread(p1,"producer1");
pt2 = new Thread(p2,"producer2");
pt3 = new Thread(p3,"producer3");
ct = new Thread(c,"consumer");
}
public void begin()
{
pt2.setPriority(Thread.NORM_PRIORITY + 5);
pt1.setPriority(Thread.NORM_PRIORITY - 4);
//pt3.setPriority(Thread.NORM_PRIORITY - 3);
pt1.start();
pt2.start();
pt3.start();
ct.start();
}
public static void main(String args[])
{
try
{
testclass t = new testclass();
t.begin();
}
catch(Exception e)
{
System.out.println("Exception caught - "+e);
}
}
}
It looks like you are dealing with threads and concurrency but not.
You are dealing with logical operators:
Your code
while(flag==false && getIndex()!=next)
wait();
If flag is true then your logical expression will be false and the execution will go on. What you really need is:
while(flag==false || getIndex()!=next)
wait();
There are so many things wrong with this code, it is hard to tell where the actual problem is. I strongly suggest that you upgrade your knowledge on threading first by reading a good book on the topic.
The major problem here is that you confuse thread priority with order of execution. In general the order of execution with threads is undefined, and unless you enforce the order, there is no order. The only thing that thread priority does is to specify which thread is put on hold if there are more running threads than CPUs that can execute them. It will not enforce any order of execution otherwise.
I.E. when several threads try to enter a synchronized function, then one of them is granted access, but which one that will be is not specified. It could be the high priority thread, but it could also be any other as well. Since all your functions are synchronized all threads are constantly put on hold, therefore even thread priority won't do a thing, because most of the time threads are waiting on their lock anyways.

Something wrong with the Peterson algorithm logic?

I am pretty new to Multithreading programming. In my code threads are trying to acquire locks around few lines. The lines work pretty fine for few context switches but then it halts (probably a deadlock).
On the other hand if use synchronized block then all works fine.
I've four classes.
1. PetersonAlgorithm.java
package com.ashish.master;
public class PetersonAlgorithm {
boolean wantCS[] = {false, false};
int turn = 1;
public void requestCS(int i) {
System.out.println("Lock requested by the thread - " + i);
wantCS[i] = true;
turn = 1 - i;
while(wantCS[1-i] && turn == 1-i);
}
public void releaseCS (int i) {
wantCS[i] = false;
turn = i - 1;
System.out.println("Lock released by the thread - " + i);
}
}
If anyone feels that above algorithm is incorrect then let me know, and feel free to make suggestions.
2. Runner.java
package com.ashish.master;
public class Runner {
public static Incrementer runnableInstance = new Incrementer();
public static Thread inc1 = new Thread(runnableInstance, "0");
public static Thread inc2 = new Thread(runnableInstance, "1");
public static void main(String args[]) {
inc1.start();
inc2.start();
try{
inc1.join();
inc2.join();
} catch (InterruptedException ex) {
System.out.println("The threads have been interrupted while waiting for the join ---> " + ex.getMessage());
}
System.out.println("The total turns taken by incrementer are ----> " + runnableInstance.turns);
}
}
3. Incrementer.java - If synchronized block is used instead of the Peterson algorithm, everything works fine.
package com.ashish.master;
public class Incrementer implements Runnable {
public long turns = 0;
public PetersonAlgorithm pa = new PetersonAlgorithm();
#Override
public void run() {
System.out.println("Thread " + this.toString() + "started.....");
while(true) {
pa.requestCS(Integer.parseInt(this.toString()));
// synchronized(this) {
if(DataStore.data < 1000000) printCriticalSection();
else break;
// }
pa.releaseCS(Integer.parseInt(this.toString()));
}
}
public void printCriticalSection() {
System.out.println("The value of the number is increased by thread " +
this.toString() +" to --> " + DataStore.increase());
turns ++;
}
#Override
public String toString() {
return Thread.currentThread().getName();
}
}
4. DataStore.java A class to mock the data source -- simply increase the number
package com.ashish.master;
public class DataStore {
public static long data = 0L;
public static long increase() {
DataStore.data += 1;
return DataStore.data;
}
}
Your runnables never observe each other's monitors (wantCS and turn) as they have different instances... Each runnable needs to work with a same shared set of monitors!
Take the blue pill and make your PetersonAlgorithm variables static volatile with synchronized block access...
Or take the red pill and you create a Class for your flag monitors (wantCS) and for your indicator monitor (turn). Then just define your runnable with one "own flag", one "observed flag" and one "indicator". Both Runnables will have the same indicator instance (therefore needs to be synchronized) while the flag instances will be crossed (the own flag of R1 will be the observed flag of R2 and the own flag of R2 the observed flag of R1). You should synchronized the flag methods too as you don't want to have a flag raised or lowered while being observed.
Then few steps:
Runnables raise their Flag
Runnables turn the shared Indicator ( set to opponent runnable's id )
Wait if opponent's flag is raised and Indicator is set to opponent.
The non waiting opponent does its stuff then lowers its flag.
The waiting opponent stops waiting (opponent's flag has been lowered), does its stuff and lowers its flag.
Each of your runnable instances has its own PetersonAlgorithm instance. Thus, the two runnables don't know anything about each other and will both always get immediate access to the critical section. Try implementing your PetersonAlgorithm class as static class with static methods. Then change the lines
pa.requestCS(Integer.parseInt(this.toString()));
// ...
pa.releaseCS(Integer.parseInt(this.toString()));
into
PetersonAlgorithm.requestCS(Integer.parseInt(this.toString()));
// ...
PetersonAlgorithm.releaseCS(Integer.parseInt(this.toString()));

Is this java class thread safe?

This isn't homework for me, it's a task given to students from some university. I'm interested in the solution out of personal interest.
The task is to create a class (Calc) which holds an integer. The two methods add and mul should add to or multiply this integer.
Two threads are set-up simultaneously. One thread should call c.add(3) ten times, the other one should call c.mul(3) ten times (on the same Calc-object of course).
The Calc class should make sure that the operations are done alternatingly ( add, mul, add, mul, add, mul, ..).
I haven't worked with concurrency related problems a lot - even less with Java. I've come up with the following implementation for Calc:
class Calc{
private int sum = 0;
//Is volatile actually needed? Or is bool atomic by default? Or it's read operation, at least.
private volatile bool b = true;
public void add(int i){
while(!b){}
synchronized(this){
sum += i;
b = true;
}
}
public void mul(int i){
while(b){}
synchronized(this){
sum *= i;
b = false;
}
}
}
I'd like to know if I'm on the right track here. And there's surely a more elegant way to the while(b) part.
I'd like to hear your guys' thoughts.
PS: The methods' signature mustn't be changed. Apart from that I'm not restricted.
Try using the Lock interface:
class Calc {
private int sum = 0;
final Lock lock = new ReentrantLock();
final Condition addition = lock.newCondition();
final Condition multiplication = lock.newCondition();
public void add(int i){
lock.lock();
try {
if(sum != 0) {
multiplication.await();
}
sum += i;
addition.signal();
}
finally {
lock.unlock();
}
}
public void mul(int i){
lock.lock();
try {
addition.await();
sum *= i;
multiplication.signal();
} finally {
lock.unlock();
}
}
}
The lock works like your synchronized blocks. But the methods will wait at .await() if another thread holds the lock until .signal() is called.
What you did is a busy loop: you're running a loop which only stops when a variable changes. This is a bad technique because it makes the CPU very busy, instead of simple making the thread wait until the flag is changed.
I would use two semaphores: one for multiply, and one for add. add must acquire the addSemaphore before adding, and releases a permit to the multiplySemaphore when it's done, and vice-versa.
private Semaphore addSemaphore = new Semaphore(1);
private Semaphore multiplySemaphore = new Semaphore(0);
public void add(int i) {
try {
addSemaphore.acquire();
sum += i;
multiplySemaphore.release();
}
catch (InterrupedException e) {
Thread.currentThread().interrupt();
}
}
public void mul(int i) {
try {
multiplySemaphore.acquire();
sum *= i;
addSemaphore.release();
}
catch (InterrupedException e) {
Thread.currentThread().interrupt();
}
}
As others have said, the volatile in your solution is required. Also, your solution spin-waits, which can waste quite a lot of CPU cycles. That said, I can't see any problems as far as correctness in concerned.
I personally would implement this with a pair of semaphores:
private final Semaphore semAdd = new Semaphore(1);
private final Semaphore semMul = new Semaphore(0);
private int sum = 0;
public void add(int i) throws InterruptedException {
semAdd.acquire();
sum += i;
semMul.release();
}
public void mul(int i) throws InterruptedException {
semMul.acquire();
sum *= i;
semAdd.release();
}
volatile is needed otherwise the optimizer might optimize the loop to if(b)while(true){}
but you can do this with wait and notify
public void add(int i){
synchronized(this){
while(!b){try{wait();}catch(InterruptedException e){}}//swallowing is not recommended log or reset the flag
sum += i;
b = true;
notify();
}
}
public void mul(int i){
synchronized(this){
while(b){try{wait();}catch(InterruptedException e){}}
sum *= i;
b = false;
notify();
}
}
however in this case (b checked inside the sync block) volatile is not needed
Yes, volatile is needed, not because an assignment from a boolean to another is not atomic, but to prevent the caching of the variable such that its updated value is not visible to the other threads who are reading it. Also sum should be volatile if you care about the final result.
Having said this, it would probably be more elegant to use wait and notify to create this interleaving effect.
class Calc{
private int sum = 0;
private Object event1 = new Object();
private Object event2 = new Object();
public void initiate() {
synchronized(event1){
event1.notify();
}
}
public void add(int i){
synchronized(event1) {
event1.wait();
}
sum += i;
synchronized(event2){
event2.notify();
}
}
public void mul(int i){
synchronized(event2) {
event2.wait();
}
sum *= i;
synchronized(event1){
event1.notify();
}
}
}
Then after you start both threads, call initiate to release the first thread.
Hmmm. There are a number of problems with your solution. First, volatile isn't required for atomicity but for visibility. I won't go into this here, but you can read more about the Java memory model. (And yes, boolean is atomic, but it's irrelevant here). Besides, if you access variables only inside synchronized blocks then they don't have to be volatile.
Now, I assume that it's by accident, but your b variable is not accessed only inside synchronized blocks, and it happens to be volatile, so actually your solution would work, but it's neither idiomatic nor recommended, because you're waiting for b to change inside a busy loop. You're burning CPU cycles for nothing (this is what we call a spin-lock, and it may be useful sometimes).
An idiomatic solution would look like this:
class Code {
private int sum = 0;
private boolean nextAdd = true;
public synchronized void add(int i) throws InterruptedException {
while(!nextAdd )
wait();
sum += i;
nextAdd = false;
notify();
}
public synchronized void mul(int i) throws InterruptedException {
while(nextAdd)
wait();
sum *= i;
nextAdd = true;
notify();
}
}
The program is fully thread safe:
The boolean flag is set to volatile, so the JVM knows not to cache values and to keep write-access to one thread at a time.
The two critical sections locks on the current object, which means only one thread will have access at a time. Note that if a thread is inside the synchronized block, no thread can be in any other critical sections.
The above will apply to every instance of the class. For example if two instances are created, threads will be able to enter multiple critical sections at a time, but will be limited to one thread per instances, per critical section. Does that make sense?

Categories