Little confused about Semaphore Class - java

I have kind of confused about the "Semaphore" class in java.util.concurrent package. Here are my code snippet:
import java.util.concurrent.Semaphore;
public class TestSemaphore {
public static void main(String[] args){
Semaphore limit = new Semaphore(2);
SemaphoreAA s = new SemaphoreAA(limit);
AAThread a = new AAThread(s);
Thread[] sThread = new Thread[100];
for(int i = 0; i<100; i++){
sThread[i] = new Thread(a,"[sThread"+i+"]");
sThread[i].start();
}
}
}
class SemaphoreAA{
private static int counter;
private Semaphore limit;
public SemaphoreAA(Semaphore limit){
this.limit = limit;
}
public void increment() throws InterruptedException{
System.out.printf("%-15s%-25s%5d%n",Thread.currentThread().getName()," : Before Increment. Current counter: ",counter);
limit.acquire();
System.out.printf("%-15s%-25s%n",Thread.currentThread().getName()," : Get the resource. Start to increment.");
counter++;
System.out.printf("%-20s%-40s%5d%n",Thread.currentThread().getName()," : Increment is done. Current counter: ",counter );
limit.release();
}
}
class AAThread implements Runnable{
private SemaphoreAA s;
public AAThread(SemaphoreAA s){
this.s = s;
}
public void run() {
try {
s.increment();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I understand it can be used to control accesses to resources. And if I set the limit to one, like this "Semaphore limit = new Semaphore(1);", it seems like a lock. It was proved. If I set the limit to two, I expect there are two threads in the given time to access to the increment() method and it might cause data race. The output might be like this:
[sThread3] : Before Increment. Current counter: 2
[sThread4] : Before Increment. Current counter: 2
[sThread3] : Get the resource. Start to increment.
[sThread4] : Get the resource. Start to increment.
[sThread3] : Increment is done. Current counter: 3
[sThread4] : Increment is done. Current counter: 3
However, though I had tried several times, the result expected didn't occur. So I wanna know if I misunderstood it. Thanks.

You understood it right.
However, though I had tried several times, the result expected didn't occur.
Just because it can appear doesn't mean it will. This is the problem with most concurrency bugs: they sometimes appear, sometimes not.
If you want to increase the likelihood of an error you can increase the number of Threads or create/start them in two different loops after each other.

Related

Why does non-thread safe counter in Java always return the correct value?

I'm trying to simulate a non-thread safe counter class by incrementing the count in an executor service task and using countdown latches to wait for all threads to start and then stop before reading the value in the main thread.
The issue is that when I run it the System.out at the end always returns 10 as the correct count value. I was expecting to see some other value when I run this as the 10 threads may see different values.
My code is below. Any idea what is happening here? I'm running it in Java 17 and from Intellij IDEA.
Counter.java
public class Counter {
private int counter = 0;
public void incrementCounter() {
counter += 1;
}
public int getCounter() {
return counter;
}
}
Main.java
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
CountDownLatch startSignal = new CountDownLatch(10);
CountDownLatch doneSignal = new CountDownLatch(10);
Counter counter = new Counter();
for (int i=0; i<10; i++) {
executorService.submit(() -> {
try {
startSignal.countDown();
startSignal.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
counter.incrementCounter();
doneSignal.countDown();
});
}
doneSignal.await();
System.out.println("Finished: " + counter.getCounter());
executorService.shutdownNow();
}
}
It's worth remembering that just because something isn't synchronised correctly, it could still perform correctly under some circumstances, it just isn't guaranteed to do so in every situation, on every JVM, on every hardware.
In other words, there is no reverse guarantee, optimisers for example are free to decide your code can be replaced at little to no cost with a correctly synchronised implementation.
(Whether that is what's actually happening here isn't obvious to me at first glance.)

How to solve multiple thread static variable incrementation?

So my problem essentially is,that even though I use static volatile int variable for incrementation some of my data doesn't remain unique which would be my goal(I number my elements).
public class Producer implements Runnable{
private String str;
private Fifo f;
private int i;
private static volatile int n=0;
public Producer(String str,int i,Fifo f) ....
public void run() {
try {
this.go();
} catch (InterruptedException e) {
;
}
}
void go() throws InterruptedException {
while(true) {
Thread.sleep(i);
int l=n++;
String k=str+" "+l+" ";
f.put(k);
System.out.println("produced "+str+" "+l+" "+System.currentTimeMillis()%100000);
}
}
}
My problem is in the function go(). I number my elements, I have multiple Producer objects running as independent threads, but sometimes they act like they have no clue whether n has been updated or not so I get same indexes.
Any ideas?
(I get what could be the problem, but I have no clue how to solve it.)
There seems to be a misunderstanding as to what volatile does. The keyword volatile introduces happens-before semantics between writes and reads. It does not, however, make multiple operations atomic.
If we were to write the semantics of n++ "by hand" (please never do this, it is for explanatory purposes only), it would look something like that:
final int result;
n = (result = n) + 1;
Ideone demo
Looking at this code, we see that we have to:
read the value of n,
store it in some temporary variable result,
increment it by 1, and
write the (incremented) value back to n
So we have multiple operations. If those operations are executed in parallel multiple times by different threads, then we can see a manifold of possible interweavings that lead to inconsistent data. For example, two threads could both read the (current) value of n. Both would increment the value by one and both would write the new value back to n. This means that two threads have executed the "increment", but the value of n has only incremented by 1 instead of 2.
We can use specialized classes - in this case AtomicInteger - to avoid this problem. The usage looks something like this:
public class Producer implements Runnable {
...
private static final AtomicInteger n = new AtomicInteger(0);
...
void go() throws InterruptedException {
while(true) {
...
int l = n.getAndIncrement();
...
}
}
}

How to fix async java code failing even with thread safety implementation?

I am working on a codebase that implements something similar to this. We are having issues with one of the threads failing to synchronize with other threads when the value of count is incremented, thus going into an infinite loop.
The problem seems to come from the non-atomic behaviour of the post-increment operator.
You can find the code Repl here NB: You may need to run the code at least 3 times to observe it.
I need support to implement increment of count by as many threads as possible in a thread safety way.
class Main {
static volatile Integer count = new Integer(0); //boxed integer is intentional to demonstrate mutable instance
static final void Log(Object o) {
System.out.println(o);
}
static synchronized void increaseCount(){
count++;
}
static synchronized Integer getCount(){
return count;
}
public static void main(String[] arg) throws InterruptedException {
new Thread(() -> {
while (getCount() != 60) {
increaseCount();
Log(count +" thread A");
}
}).start();
new Thread(() -> {
while (getCount() != 20) {
increaseCount();
Log(count +" thread B");
}
}).start();
new Thread(() -> {
while (getCount() != 50) {
increaseCount();
Log(count+" thread C");
}
}).start();
}
}
If many threads are incrementing a shared counter, there is no guarantee about which thread will see a particular value of the counter. To make sure a particular thread sees a particular value, that thread has to see every value of the counter. And then you might as well just have one thread, because they are all working in lockstep with each other.
If you want to do some work for every value of the counter, with special handling for particular values, and you want to parallelize that workload, every thread needs to be prepared to perform the special handling. Here's an example of how you could do that:
class Main {
private static class Worker implements Runnable {
private final AtomicInteger counter;
private final Set<Integer> triggers;
Worker(AtomicInteger counter, Set<Integer> triggers) {
this.counter = counter;
this.triggers = triggers;
}
public void run() {
String name = Thread.currentThread().getName();
while (!triggers.isEmpty()) {
int value = counter.getAndIncrement();
try { /* Simulate actually doing some work by sleeping a bit. */
long delay = (long) (-100 * Math.log(1 - ThreadLocalRandom.current().nextDouble()));
TimeUnit.MILLISECONDS.sleep(delay);
} catch (InterruptedException ex) {
break;
}
boolean triggered = triggers.remove(value);
if (triggered) {
System.out.println(name + " handled " + value);
} else {
System.out.println(name + " skipped " + value);
}
}
}
}
public static void main(String[] arg) throws InterruptedException {
AtomicInteger counter = new AtomicInteger();
Set<Integer> triggers = new ConcurrentSkipListSet<>();
triggers.add(60);
triggers.add(20);
triggers.add(50);
int concurrency = 4;
ExecutorService workers = Executors.newFixedThreadPool(concurrency);
for (int i = 0; i < concurrency; ++i) {
workers.execute(new Worker(counter, triggers));
}
workers.shutdown();
}
}
The number of worker threads can be adjusted so that it makes sense given the number of cores on your machine, and the real workload (how CPU or I/O intensive the tasks are).
In this approach, each value of the counter is processed by just one thread, and it doesn't matter which thread gets a "sentinel" value. But, when all the sentinel values have been processed, all the threads shut down. Threads coordinate with each other through the counter, and the set of "triggers", or sentinel values that they need to handle.

Java: Why is my synchronized output still so random

So I'm practicing with synchronization for the first time. I'm trying to implement a practice concept that was described in general on the Oracle Java Concurrency tutorial.
The idea is to have a special Counter object, with methods to increment, decrement, and show value. My goal was to get it run by two different threads to generate random conflicts, and to then solve those conflicts through synchronization. So far I feel like the second part is not working, and I can't figure out what I'm doing wrong.
The code I'm pasting below is simple. There are two threads, with two runnables. Each runnable:
1) contains a reference to the same, single Counter object
2) runs a loop five times
3) sleeps for 1 second each time the loop runs
4) prints the current value of the Counter.
The only difference between MyRunnable1 & MyRunnable2 is that the first one increments the counter, and the second one decrements the counter.
Obviously when I ran it without synchronized methods it produced random results. But even after I synchronized the methods, the results were still apparently random.
SAMPLE RESULTS 1:
1
0
1
0
1
0
-1
0
1
0
SAMPLE RESULTS 2:
-1
0
1
0
1
0
1
0
-1
0
WHAT I THINK IT SHOULD BE: It should consistently go 1 0 1 0 1 0 etc etc until all the loops are finished. If I'm wrong there, if it's the way I'm thinking about thread behavior, please point that out.
Below is my code. All thoughts/advice appreciated. This is my first attempt at using synchronization in any way, I want to get it down because it's such an important concept.
public class CounterSync {
public static void main(String[] args){
Counter c = new Counter();
Thread t1 = new Thread(new MyRunnable1(c));
Thread t2 = new Thread(new MyRunnable2(c));
t1.start();
t2.start();
System.out.println("Done");
}
public static class Counter{
private int c = 0;
public synchronized void increment(){
c++;
}
public synchronized void decrement(){
c--;
}
public synchronized int value(){
return c;
}
}
public static class MyRunnable1 implements Runnable{
private Counter c;
public MyRunnable1(Counter c){
this.c = c;
}
#Override
public void run(){
try{
for(int i = 0; i < 5; i++){
Thread.sleep(1000);
c.increment();
System.out.println(c.value());
}
}catch(InterruptedException ex){
ex.printStackTrace();
}
}
}
public static class MyRunnable2 implements Runnable{
private Counter c;
public MyRunnable2(Counter c){
this.c = c;
}
#Override
public void run(){
try{
for(int i = 0; i < 5; i++){
Thread.sleep(1000);
c.decrement();
System.out.println(c.value());
}
}catch(InterruptedException ex){
ex.printStackTrace();
}
}
}
}
Synchronization does not mean ordering. Perhaps the word 'synchronization' is misleading. In your case, when one has synchronized methods, it means that at a given instant maximum one thread can be running a synchronized method on the object in question.
You can read 'synchronized' as 'one at a time'.
Whenever you have more than one thread running, how much each thread will progress is decided by the system. Further, Thread.sleep is guaranteed to sleep at least for the given interval, but not exact. The two facts combined will give you the random ordering.

CyclicBarrier not working as expected

I am trying to simulate a triatlon competition using CyclicBarrier but it doesn't work as expected and I don't know why.
Each part of the competition has to wait till all the runners have completed the previous one, but it seems like it's waiting forever.
This is the piece of code for the phase one:
class Runner implements Runnable
{
private CyclicBarrier bar = null;
private static int runners;
private static double[] time;
private int number;
public static String name;
public Runner(int runners, String name)
{
time = new double[runners];
for (int i=0; i<runners; i++)
time[i] = 0;
this.name= name;
}
public Runner(CyclicBarrier bar, int number)
{
this.bar = bar;
this.number = number;
}
public void run()
{
try { int i = bar.await(); }
catch(InterruptedException e) {}
catch (BrokenBarrierException e) {}
double tIni = System.nanoTime();
try { Thread.sleep((int)(100*Math.random()); } catch(InterruptedException e) {}
double t = System.nanoTime() - tIni;
time[number] += t;
}
}
public class Triatlon
{
public static void main(String[] args)
{
int runners = 100;
CyclicBarrier Finish_Line_1 = new CyclicBarrier (runners);
Runner c = new Runner(runners, "Triatlon");
ExecutorService e = Executors.newFixedThreadPool(runners);
for (int i=0; i<runners; i++)
e.submit(new Runner(Finish_Line_1, i));
System.out.println(Finish_Line_1.getNumberWaiting()); // this always shows 99
try { int i = Finish_Line_1.await(); }
catch(InterruptedException e01) {}
catch (BrokenBarrierException e02) {}
System.out.println("Swimming phase completed");
// here the rest of the competition, which works the same way
}
}
You have an off-by-one error: you create a CyclicBarrier for 100 threads, but execute 101 awaits, the one-off being in the main method. Due to the semantics of the cyclic barrier, and subject to nondeterministic conditions, your main thread will be the last to execute await, thereby being left alone waiting for another 99 threads to join in.
After you fix this problem, you'll find out that the application keeps running even after all work is done. This is because you didn't call e.shutdown(), so all the threads in the pool stay alive after the main thread is done.
BTW getNumberWaiting always shows 0 for me, which is the expected value after the barrier has been lowered due to 100 submitted threads reaching it. This is nondeterministic, however, and could change at any time.
CyclicBarrier cycles around once all parties have called await and the barrier is opened. Hence the name.
So if you create it with 5 parties and there are 6 calls to await the last one will trigger it to be waiting again for 4 more parties to join.
That's basically what happens here as you have the 1 extra await call in your main. It is waiting for another runners-1 calls to happen.
The simple fix is to create the CyclicBarrier with runners+1 parties.

Categories

Resources