'Semaphores used for signaling in threads not working(concurrency issue)
in this project I am trying to do some concurrency among threads using semaphores as signaling, however the concurrency is not working at all. I can only use acquire and release and no synchronized keyword methods allowed. I read countless webpages and it says that
// do something
acquire()
release()
//do something
Which I understand but in this program I am trying to test signals with a semaphore between threads, for example user requests deposit and teller should say deposit completed.However my signals(semaphores) are not working as I want to print in order for example
I need to deposit Deposit is complete
instead I get this
Customer0created
I need to deposit
I have withdrawn <---
Customer0joined from main
Teller0created
You wanna withdrawal? <---- (out of order)
Deposit is complete
Regardless how i reorder them or how much i read the semaphore signaling to comm threads is not working.
[code]import java.util.concurrent.Semaphore;
public class Threads {
private static Semaphore depositTransaction = new Semaphore (1, true);
private static Semaphore withdrawal = new Semaphore (1, true);
public static void main(String[] args)
{
final int customerThreads = 1;
final int tellerThreads = 1;
final int loanThreads = 1;
Customer thr[] = new Customer[customerThreads]; //
Thread cThread[] = new Thread[customerThreads]; //
for (int i= 0; i < customerThreads; i++)
{
thr[i]= new Customer(i);
cThread[i] = new Thread(thr [i]);
cThread[i].start();
}
for ( int i = 0; i < customerThreads; i++ )
{
try {
cThread[i].join();
System.out.println("Customer"+i + "joined from main");
}
catch (InterruptedException e)
{
}
}
Teller thr1[] = new Teller[tellerThreads];
Thread tThread[] = new Thread[tellerThreads];
for (int b = 0; b< tellerThreads; b++)
{
thr1[b] = new Teller(B)/>;
tThread[b]= new Thread(thr1 [b]);
tThread[b].start();
}
}
static class Customer implements Runnable
{
private int customerNumber = 0;
private int balance = 0;
Customer(int cn)
{
this.customerNumber = cn;
balance = 1000;
System.out.println("Customer"+ customerNumber + "created");
}
public void run()
{
try
{
System.out.println("I need to deposit");
depositTransaction.acquire();// signal
}
catch(InterruptedException e)
{
Thread.currentThread().interrupt();
e.printStackTrace();
}
withdrawal.release();
System.out.println("I have withdrawn");
}
}
static class Teller implements Runnable
{
private int tellerNumber = 0;
Teller(int tn)
{
this.tellerNumber = tn;
System.out.println("Teller"+ tellerNumber +"created");
}
public void run()
{
try
{
System.out.println("You wanna withdrawal?");
withdrawal.acquire();
}
catch(InterruptedException e)
{
Thread.currentThread().interrupt();
}
depositTransaction.release();
System.out.println("Deposit is complete");
}
}
}[/code]
Solution 1:[1]
Here is a program that uses a semaphore to play ping pong. It is very similar to what you need for your goal. This program has one thread that will print PING, and the other prints PONG. It uses a semaphore to ensure that PING is printed first, then PONG, then PING and so on.
Notice how this program uses two semaphores, and that it starts both semaphores at zero. This means that when the threads call acquire() on it, they will block. You have been using the value of one, which means that neither thread would block and that both would rush ahead.
Now that all threads have blocked, we need to get one of them to start. We send a 'release()' signal to the semaphore that the thread that we want to start up on. That will increment the semaphore by one, and the thread blocked in acquire() will wake up and decrement it again before proceeding with its all important job of printing PING or PONG.
Remember the following about semaphores:
- A semaphore contains an integer value (called a permit count)
- acquire() will block until the integer value is greater than zero; when greater than zero the count will be decremented by one before exiting
- release() never blocks. It only ever increments the integer value by one, and as a side effect wakes up any method that were blocked in a call to acquire().
Thus for a game of ping pong to work: (ascii art below scrolls to the right)
s1=0 -- release() --> s1=1 s1=0 s2=0 s2=0 s2=1 thread1=blocked thread1 runs -- calls s2.release() --> thread1 blocked thread2=blocked thread2=blocked thread2 runs
Notice how the values of s1 and s2 oscilate between 0 and 1, but we do not allow them both to have the value of 1 at the same time. If they were ever to both equal 1, then both thread1 and thread2 would be able to run at the same time. Which would be known as a race condition, as the order of their execution would be unpredictable.
public class PingPong {
public static void main( String[] args ) throws InterruptedException {
final Semaphore s1 = new Semaphore(0);
final Semaphore s2 = new Semaphore(0);
final AtomicInteger countDown = new AtomicInteger( 10 );
Thread threadA = new Thread() {
public void run() {
try {
System.out.println("threadA started");
while (countDown.get() > 0) {
s1.acquire();
System.out.println( "PING" );
s2.release();
countDown.decrementAndGet();
}
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println("threadA finished");
}
};
Thread threadB = new Thread() {
public void run() {
try {
System.out.println("threadB started");
while (countDown.get() > 0) {
s2.acquire();
System.out.println( "PONG" );
s1.release();
countDown.decrementAndGet();
}
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println("threadb finished");
}
};
threadA.start();
threadB.start();
s1.release();
}
}
Solution 2:[2]
You are not using semaphores correctly for what you want to do. As I get it, you want to start the customer thread, then block until the teller threads finishes then finish the customer thread.
Right now your semaphore do close to nothing. They will prevent multiple customer threads from running at the same time, but within your acquire / release block, nothing happens.
If you want to synchronize between customer and teller, both classes need to use the same Semaphore
What I would suggest is this :
remove the join operation for now
create the depositTransaction semaphore with count 0, so the first acquire will block.
Start a customer thread
The thread will block waiting for a deposit
Start a teller thread
make the deposit and release the depositTransaction semaphore
the customer thread will unblock
you can now join both threads
Edit :
I don't think that your idea of adding tons of semaphore for every action is a good idea. You will end up with complex locking and deadlocks all over the place. What I would suggest is to limit the number of semaphore and implement messages between the threads. The semaphore will tell the other one (Client tells Teller and vice-versa) to check the messages after pushing one.
Start customer thread
push message that customer is waiting
signal for new customer request
wait for teller signal
Start teller thread
acquire sem for new customer request
check message
do stuff
signal customer that stuff is done
messages will then be "withdrawal customer 0" or any other action you want to implement
Solution 3:[3]
Would suggest you to look at one of the standard examples and rework your code. Semaphore is very easy to use and all we need to do is acquire the lock when a thread accesses the shared resource and release the lock when it it is done.
There is nice example with a producer and a consumer thread protecting a shared resource here. Semaphore Example with a Producer and Consumer thread
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 |
