Java: Why is my synchronized output still so random - java

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.

Related

Why do these synchronized methods keep giving me different outputs?

I need this threads that have access to the same data to be execute simultaneously without messing around with each other, so instead using Thread.join() I've been trying with synchronized methods. Problem is that I see no change at all, it keep giving me the same result that I had before using them. I don't even know what exactly I'm doing wrong, synchronized
methods suppose to prevent other synchronized methods to execute until they are done, right? Hope you can give me some clue about what is goin' on.
public class ThreadSync{
public static void main(String[] args) throws InterruptedException {
//if execute properly
//output can't be other than 0
while(true) {
ChangeValue counter = new ChangeValue();
Threads t = new Threads(counter,"up");
Threads t2 = new Threads(counter,"down");
Threads t3 = new Threads(counter,"print");
t.start();
t2.start();
t3.start();
}
}
}
class Threads extends Thread{
Threads(ChangeValue obj, String act){
counter = obj;
action = act;
}
#Override
public void run() {
switch(action) {
case ("up"): counter.up(); break;
case ("down"): counter.down(); break;
case ("print"): counter.print(); break;
}
}
ChangeValue counter;
String action;
}
class ChangeValue{
public synchronized void up() { value++; }
public synchronized void down() { value--; }
public synchronized void print() { System.out.println(value); }
public int value = 0;
}
The synchronization just ensures that the methods are not executed at the same time. However, it does not guarantee any execution order.
You need to ensure that print() is not executed before the other threads have terminated. This could be achieved by joining the threads. To do so, execute
t.join();
t2.join();
either before starting the print thread or before executing its logic.
Note that the synchronization is still sensible because it ensures that the increment and decrement operations are executed atomically. That is, that reading, incrementing, and writing count when executing count++ are executed at once
(see also: Why is i++ not atomic?). Thereby it prevents the following execution sequence:
[Thread "up"]: load count with value 0
[Thread "down"]: load count with value 0
[Thread "up"]: increment count to 1
[Thread "down"]: decrement count to -1
[Thread "up"]: store count with value 1
[Thread "down"]: store count with value -1
(This is a "lost update" in database terms.)
synchronized prevens your thread from accessing the field simultaneously, but of course it provides no guarantee regarding the order in which the threads execute.
For example, if, by pure chance, the "Up" thread executes first, the "Print" thread second and the "Down" thread last, the output will be 1, even though the counter value is 0 after all threads are finished.

I don't get how threads work in this case

The following code is shows how no race condition in thread works, but I don't get the difference between with the synchronized and without it. I thought the static variable counter will be added to 20000 anyway but it turned out that without synchronized counter would be less than 20000. Can you please explain how threads work in this case? Also, in Java, are threads are actually not running "concurrently", instead are they taking turns to run for a while?
public class NoRaceCondition implements Runnable {
private static int counter = 0;
private static Object gateKeeper = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new NoRaceCondition());
Thread t2 = new Thread(new NoRaceCondition());
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) { e.printStackTrace(); }
System.out.printf("counter = %d\n", counter);
}
public void run() {
synchronized (gateKeeper) {
for (int i = 0; i < 10000; i++) {
{
counter++;
}
}
}
}
}
You can think of count++ as 3 separate steps.
read the value of count
increment the value
override count with the new incremented value
When multiple thread execute the above steps concurrently, race conditions may occur. 1 example of race condition is
Let count = 1
Let there be 2 threads named A and B
Thread A reads the value of count and get 1
Thread B reads the value of count and get 1
Thread A increments its value and get 2
Thread B increments its value and get 2
Thread A writes the value to count
count is now 2
Thread B writes the value to count
count is now 2 again when it's expected to be 3 after 2 increments

Invoking synchronized getter and setter

I am trying to practice synchronize keyword with methods.
I wrote the following code:
Adder class:
public class Adder implements Runnable{
Counter counter;
Adder(Counter counter){
this.counter = counter;
}
public void run() {
for (int i=0; i<100; i++)
counter.setCount(counter.getCount()+1);
}
}
Counter class:
public class Counter {
private int count = 0;
public synchronized void setCount(int val){
count = val;
}
public synchronized int getCount(){
return count;
}
}
main:
public class main {
public static void main(String[] args) {
Counter counter = new Counter();
Adder adder = new Adder(counter);
Thread t1 = new Thread(adder);
Thread t2 = new Thread(adder);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter.getCount());
}
}
I would expect the output of this to be 200, but it's not deterministic (theoretically, can have any value between 0-200). I suspect the problems is that I am using the getter and setter inline, i.e.
counter.setCount(counter.getCount()+1);
For some reason this "breaks" the mutual exclusion that I am trying to achieve with synchronization, but I can't see why.
I implemented the 1's addition with count++ like so:
public synchronized void add1(){
count++;
}
This worked, maybe because this way I use only one function instead of two inline. Could you explain why the first implementation doesn't work?
Calling the getter and subsequent calling of setter is two independent operations. "Set the result of getter plus one" is not atomic here. So you may perfectly have two gets returning the same value, and two sets of the same value increased by one.
Assume count is 100. You have two threads calls calling the getter, both getting 100. Then they both call the setter, setting 101. So the counter is now 101, not 102 - and both threads "were there" already.
So the result is non-deterministic and depends on the actual order of get/set operations from the two threads.
counter.setCount(counter.getCount()+1); is NOT atomic and it involves 3 steps:
(1) Read the value of count
(2) Add one to count
(3) Write the value of count
In the first approach, you are getting the locks independently i.e., in between the get and set calls of one thread there will be an interference of other threads. So you can't guarantee that the first thread read value is the same as when it comes for the writing.
In the second approach, you are holding the lock and performing all of the above 3 steps, so you will not find any problem.
Also, you can also solve your problem by using the threadsafe AtomicInteger class.

Divide Loop Execution According to Threads In Java

suppose i have a method run as following,
public void run()
{
for(i=loopstart;i<loopend;i++){
//some code here to execute. no dependency exists
}
loopstart & loopend variables have the min and max value of loop execution.
now what i have to do is to divide this loop execution in 2 to 5 threads in order to execute in parallel. to accomplish this, i have changed this method as
public void run()
{
for(i=thread_start; i<thread_end; i++)
//some code here to execute.
}
the variables thread_start and thread_end are the ranges each thread has to run. so how it would be best to divide loop execution. suppose i have the loop execution in the range
5-94
and i want to divide it to many ranges for execution depending on number of threads.
e.g.
threads ranges
2 5-44, 45-94
3 5-34, 35-65, 66-94
these are just examples (not exact). i want to divide its execution on the basis of threads available.
so for 2 threads,
thread_start=5 ,thread_end=44 1st thread
thread_start=45 ,thread_end=94 2nd thread.
how should (using java code) i divide loop execution in almost same length ranges?
public class Looper implements Runnable {
private int start;
private int end;
public Looper(int start, int end){
this.start = start;
this.end = end;
}
#Override
public void run() {
for(int i=start; i<end; i++){
System.out.println("thread id : " + Thread.currentThread().getId() + "; index : " + i) ;
}
}
}
public class Test {
public static void main(String[] args){
Thread looper1 = new Thread(new Looper(1,1000));
Thread looper2 = new Thread (new Looper(1001,2000));
looper1.start();
looper2.start();
}
}
this is what you need? If you need to get available Threads at runtime, you might consider using ThreadPool.

Concurrent download counters in Java

As part of our University coursework we have to make a multi threading download server in Java.
Everything is running smoothly apart from one bit : we have to have the server show the total number of downloads for each item each time it is downloaded. So far I have gotten it to work unless both clients request it at the same time. The code is below, If any one has any ides I would be very grateful. Also we must include thread.sleep part and must increment the counter in that convoluted way.
//Snipper from Protocol.java
if (theInput.equals("1")) {
theOutput = "The program displays a message... Another? Y or N";
DownloadCounter counter = new DownloadCounter();
count = DownloadCounter.getcount();//count is a var in Protocol.java it is static
int tmp = count;
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
System.out.println("sleep interrupted");
}
count = tmp + 1;
DownloadCounter.setcount(count);
System.out.println("Download Total " + count);
state = ANOTHER;
The DownloadCounter:
//DownloadCounter.java
public class DownloadCounter {
private static int count;
public static synchronized int getcount(){
return count;
}
public static synchronized void setcount(int num){
DownloadCounter.count = num;
}
}
The fundamental problem is that you have two threads doing a get, increment and set, so consider this situation:
Thread 1: set(5) // now count is 5
Thread 1: get() // Thread 1 gets 5
Thread 2: get() // Thread 2 gets 5
Thread 2: increments its local copy of count to 6
Thread 1: increments its local copy of count to 6
Thread 2: set(6) // now the count is 6
Thread 1: set(6) // the count is still 6, but it should be 7!!!
The solution is to implement an increment method which increments the count in a thread safe manner:
public synchronized void increment()
{
count++;
}
You can also use an AtomicInteger and avoid the locking:
AtomicInteger count = new AtomicInteger(0);
public int getCount()
{
return count.get();
}
public void increment()
{
count.incrementAndGet();
}
You also stated that the counter should count the number of downloads for each item, however, your current code will not do that. Your current counter will count ALL of the downloads for ALL of the items. Hint: you're making everything in DownloadCounter static and that's not going to work well if you want to have a separate counter for each item.
DownloadCounter needs a method for incrementing. There's no safe way to increment the counter with only a getCount and setCount method.
Java has a class AtomicInteger for handling just this type of thing.
Also you are only calling static methods on DownloadCounter, so there is no need to create a new instance.
The key to make it correct is precisely to make the get/increment/set an atomic operation. Instead of the setCount method, there should be a synchronized incrementCount() method.
You could also avoid the synchronization completely by using an AtomicInteger and use its incrementAndGet() method inside the incrementCount() method.
Note that the instruction DownloadCounter counter = new DownloadCounter(); is completely unnecessary. The class should have a private constructor to prevent such unnecessary instantiations.

Categories

Resources