Solving Counter Problem in Java Thread With synchronized method and block - java

I just wrote code for counter problem in a thread. When I add synchronized on Method its working fine but when I use synchronized block inside a method it does not work, why? Something I am missing, I guess.
public class CounterProblem {
class Counter implements Runnable {
private Integer count = 0;
#Override
public void run() {
for(int i = 0; i < 10000; i++) {
increment();
}
}
// THIS GIVES 20000 which is correct every time.
public synchronized void increment() {
count++;
}
// THIS GIVES wrong every time. WHY ?
// public void increment() {
// synchronized(count) {
// count++;
// }
// }
}
public static void main(String[] args) throws InterruptedException {
CounterProblem counterProblem = new CounterProblem();
Counter counter = counterProblem.new Counter();
Thread thread1 = new Thread(counter);
Thread thread2 = new Thread(counter);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(counter.count);
}
}

java.lang.Integer's aren't mutable. When you increment an Integer, you unbox it to a primitive int, increment it, and then autobox the result to a different Integer instance. This means your synchronized block synchronizes on a different object every time, making it pointless - as you've seen yourself.

Related

Java Multithreading - Threadsafe Counter

I'm starting off with a very simple example in multithreading. I'm trying to make a threadsafe counter. I want to create two threads that increment the counter intermittently to reach 1000. Code below:
public class ThreadsExample implements Runnable {
static int counter = 1; // a global counter
public ThreadsExample() {
}
static synchronized void incrementCounter() {
System.out.println(Thread.currentThread().getName() + ": " + counter);
counter++;
}
#Override
public void run() {
while(counter<1000){
incrementCounter();
}
}
public static void main(String[] args) {
ThreadsExample te = new ThreadsExample();
Thread thread1 = new Thread(te);
Thread thread2 = new Thread(te);
thread1.start();
thread2.start();
}
}
From what I can tell, the while loop right now means that only the first thread has access to the counter until it reaches 1000. Output:
Thread-0: 1
.
.
.
Thread-0: 999
Thread-1: 1000
How do I fix that? How can I get the threads to share the counter?
You could use the AtomicInteger. It is a class that can be incremented atomically, so two seperate threads calling its increment method do not interleave.
public class ThreadsExample implements Runnable {
static AtomicInteger counter = new AtomicInteger(1); // a global counter
public ThreadsExample() {
}
static void incrementCounter() {
System.out.println(Thread.currentThread().getName() + ": " + counter.getAndIncrement());
}
#Override
public void run() {
while(counter.get() < 1000){
incrementCounter();
}
}
public static void main(String[] args) {
ThreadsExample te = new ThreadsExample();
Thread thread1 = new Thread(te);
Thread thread2 = new Thread(te);
thread1.start();
thread2.start();
}
}
Both threads have access to your variable.
The phenomenon you are seeing is called thread starvation. Upon entering the guarded portion of your code (sorry I missed this earlier), other threads will need to block until the thread holding the monitor is done (i.e. when the monitor is released). Whilst one may expect the current thread pass the monitor to the next thread waiting in line, for synchronized blocks, java does not guarantee any fairness or ordering policy to which thread next recieves the monitor. It is entirely possible (and even likely) for a thread that releases and attempts to reacquire the monitor to get hold of it over another thread that has been waiting for a while.
From Oracle:
Starvation describes a situation where a thread is unable to gain regular access to shared resources and is unable to make progress. This happens when shared resources are made unavailable for long periods by "greedy" threads. For example, suppose an object provides a synchronized method that often takes a long time to return. If one thread invokes this method frequently, other threads that also need frequent synchronized access to the same object will often be blocked.
Whilst both of your threads are examples of "greedy" threads (since they repeatedly release and reacquire the monitor), thread-0 is technically started first, thus starving thread-1.
The solution is to use a concurrent synchronization method that supports fairness (e.g. ReentrantLock) as shown below:
public class ThreadsExample implements Runnable {
static int counter = 1; // a global counter
static ReentrantLock counterLock = new ReentrantLock(true); // enable fairness policy
static void incrementCounter(){
counterLock.lock();
// Always good practice to enclose locks in a try-finally block
try{
System.out.println(Thread.currentThread().getName() + ": " + counter);
counter++;
}finally{
counterLock.unlock();
}
}
#Override
public void run() {
while(counter<1000){
incrementCounter();
}
}
public static void main(String[] args) {
ThreadsExample te = new ThreadsExample();
Thread thread1 = new Thread(te);
Thread thread2 = new Thread(te);
thread1.start();
thread2.start();
}
}
note the removal of the synchronized keyword in favor of the ReentrantLock within the method. Such a system, with a fairness policy, allows long waiting threads a chance to execute, removing the starvation.
Well, with your code I don't know how to get "exactly" intermittently, but if you use Thread.yield() after call incrementCounter() you will have a better distribution.
public void run() {
while(counter<1000){
incrementCounter();
Thread.yield();
}
}
Otherwise, to get what you propose, you can create two different thread class (ThreadsExample1 and ThreadsExample2 if you want), and another class to be a shared variable.
public class SharedVariable {
private int value;
private boolean turn; //false = ThreadsExample1 --> true = ThreadsExample2
public SharedVariable (){
this.value = 0;
this.turn = false;
}
public void set (int v){
this.value = v;
}
public int get (){
return this.value;
}
public void inc (){
this.value++;
}
public void shiftTurn(){
if (this.turn){
this.turn=false;
}else{
this.turn=true;
}
}
public boolean getTurn(){
return this.turn;
}
}
Now, the main can be:
public static void main(String[] args) {
SharedVariable vCom = new SharedVariable();
ThreadsExample1 hThread1 = new ThreadsExample1 (vCom);
ThreadsExample2 hThread2 = new ThreadsExample2 (vCom);
hThread1.start();
hThread2.start();
try {
hThread1.join();
hThread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
And you have to change your line static int counter = 1; // a global counter
for private SharedVariable counter;
And the new run is:
public void run() {
for (int i = 0; i < 20; i++) {
while (!counter.getTurno()){
Thread.yield();
}
System.out.println(this.counter.get());
this.counter.cambioTurno();
}
}
}
Yes, it is another code, but I think it can help you a little bit.

Synchronized method does not work as expected

I have a variable which is shared by two threads. The two threads will do some operations on it. I don't know why the result of sharedVar is different every time I execute the program.
public class Main
{
public static int sharedVar = 0;
public static void main(String[] args)
{
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.start();
mt2.start();
try
{
// wait for the threads
mt1.join();
mt2.join();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
System.out.println(sharedInt); // I expect this value to be 20000, but it's not
}
}
The following is the class "MyThread"
public class MyThread extends Thread
{
private int times = 10000;
private synchronized void addOne()
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar ++;
}
}
#Override
public void run()
{
addOne();
}
}
The final result of sharedVar sometimes are 13735, 12508, or 18793; but never 20000, which is the result I expect. Another interesting thing about the program is when times=1000. I always get 2000 as the final result.
Can anyone explain this phenomenon?
A synchronized method protects the resource this that means that your code is equivalent to:
private void addOne()
{
synchronized(this)
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar ++;
}
}
}
But you have 2 objects for which addOne method is called. That means this for mt1.addOne is not the same than this for mt2.addOne and therefore you don't have a common resource of synchronization.
Try changing yout addOne code to:
private void addOne()
{
synchronized(MyThread.class)
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar ++;
}
}
}
And you will observe the expected behaviour. As the comments below suggest, it is better to use a different object than MyThread.class for synchronization since class objects are accesible from many points and it is easy that other code may try to synchronize using the same object.
When you use synchronized on non-static method, you use current object as monitor.
When you use synchronized on static method, you use current object of class (ClassName.class static field) as monitor.
In your case, you use synchronized on Thread's object (2 different instances), so two different threads will modify your sharedVar static field at same time.
You can fix it in different ways.
Move addOne method to Main and make it static.
private static synchronized void addOne(int times)
{
for (int i = 0; i < times; ++i)
{
sharedVar++;
}
}
Or you can create class called SharedVar with field private int var; and method synchronized void addOne(int times) and pass single instance of SharedVar to your treads.
public static void main(String[] args)
{
SharedVar var = new SharedVar();
MyThread mt1 = new MyThread(var);
MyThread mt2 = new MyThread(var);
mt1.start();
mt2.start();
try
{
// wait for the threads
mt1.join();
mt2.join();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
System.out.println(var.getVar()); // I expect this value to be 20000, but it's not
}
But if you need only one integer to be changed in multiple threads, you can use classes from java.til.concurrent.*, like AtomicLong or AtomicInteger.
Define sharedVar as an AtomicLong instead of int. Making the function synchronized works as well but it is less efficient because you only need the increment to be synchronized.
When a thread is about to execute a 'synchronized' instance method, it aqcuires the lock on the Object(to be precise, lock on that object monitor).
So in your case, Thread mt1 acquires lock on Object mt1 and Thread mt2 acquires lock on Object mt2 and they do not block each Other as the two threads are working on two different locks.
And when two threads modify a shared variable concurrently(not synchronized way), the result is unpredictable.
Well about the case of value 1000, for smaller inputs the interleaved execution might have resulted in correct result(luckily).
Sol : remove the synchronized keyword from addOne method and make sharedVal as type of 'AtomicInteger'
Join the thread immediately after start method. From this thread-1 will start and go to dead state after that thread-2 will start and go to dead state. So it will print your expected output always.
Change the code as shown below:-
public class Main{
public static int sharedVar = 0;
public static void main(String[] args)
{
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
try
{
mt1.start();
mt1.join();
mt2.start();
mt2.join();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
System.out.println(sharedVar);
}
}
class MyThread extends Thread
{
private int times = 1000000;
private synchronized void addOne()
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar++;
}
}
#Override
public void run()
{
addOne();
}
}

Why volatile and synchronized statements cannot avoid thread interference here?

package simple;
public class ThreadInterference {
public static volatile Integer count = 1000;
public static class MyThread implements Runnable {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
count++;
count--;
count++;
count--;
}
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println(count);
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
Thread t3 = new Thread(new MyThread());
Thread t4 = new Thread(new MyThread());
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(count);
}
}
The count variable is marked as volatile but the output is:
1000
1230
If I change to synchronized statements, thread interference also happens:
package simple;
public class ThreadInterference {
public static Integer count = 1000;
public static class MyThread implements Runnable {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
synchronized(count) {
count++;
count--;
count++;
count--;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println(count);
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
Thread t3 = new Thread(new MyThread());
Thread t4 = new Thread(new MyThread());
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(count);
}
}
output of this time is:
1000
1008
Why?
As others have noted, you have two separate problems. The first one is that count++ (and count--) isn't an atomic operation, even for primitive int types. So this won't work without some sort of locking or other concurrency handling. For count++ where count is an int, the compiler generates something like the following byte code instructions:
getstatic count
iconst_1
iadd
putstatic count
This is not likely to be atomic even if/when compiled to native code.
The second problem is that you are not locking on a consistent object, so operations are not serialised. The code:
count++; // "count" is an "Integer" object type.
Creates a new object. In essence it does something like the following:
count = Integer.valueOf(count.intValue() + 1);
So your count object is getting replaced by a new object, and subsequent entry into the synchronized section will be synchronizing against a different object.
As a safety tip, if you are using synchronized (someObject), where someObject is a class or instance field, then it's a good idea to make that field final. That way it can't be inadvertently reassigned to a different value.
There are two straightforward solutions to the problem that I can think of. One with locking against a specific object used for locking like so:
public class ThreadInterference {
public static final Object COUNT_LOCK = new Object();
public static int count = 1000; // Either "int" or "Integer" OK, depending on need
public static class MyThread implements Runnable {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
synchronized(COUNT_LOCK) {
count++;
count--;
count++;
count--;
}
}
}
}
// And so on...
}
Another option is to use an AtomicInteger which may give better concurrent performance, if that matters:
public class ThreadInterference {
public static AtomicInteger count = new AtomicInteger(1000);
public static class MyThread implements Runnable {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
count.incrementAndGet();
count.decrementAndGet();
count.incrementAndGet();
count.decrementAndGet();
}
}
}
// And so on...
}
I believe what is happening is this:
count++ tries to increment an Integer, which is immutable. The compiler must create a new Integer and refer to it as "count". Synchronization locks on the former count will then behave unexpectly. Somebody really smart could probably work it out...
Change count to a primitive int and synchronize on something else to see what happens. Or use an AtomicInteger.
Main takeaway is don't increment Integers! unless you are sure.
Instead of synchronizing count,
Try doing increment/decrement method that are themselves synchronized...
public static synchronized decrementCount()
{
count--;
}
public static synchronized incrementCount()
{
count++;
}
And call them instead of directly decrementing/incrementing.
Also, you should use atomic value if you are only doing a counter which prevent thread interference without resorting to synchronization.
Anyway, check this doc which show you how to do a synchronized counter with synchronized methods or atomic values : http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html
When you are doing this, you are doing it wrong.
public static volatile Integer count = 1000;
for (int i = 0; i < 10000; i++) {
synchronized(count) {
count++;
count--;
count++;
count--;
}
}
Integer is immuttable. That means, when you are doing count++, it created a new Integer object, and assigned count with that new object. Meanwhile, synchronized part still reference the old object. So there exist a chance when every thread reached synchronized block with different object.
You should use variable that doesn't point to different object when the process happened.

Basic multi-threading issue

package demo5;
class Process extends Thread {
static int counter = 0;
public static synchronized void increment() { counter++; }
public void run() {
for (int i = 0; i < 1000000; i++)
{
increment();
}
System.out.println("Done.");
}
}
public class App {
public static void main(String[] args) throws InterruptedException {
Process p1 = new Process();
Process p2 = new Process();
p1.start();
p2.start();
p1.join();
p2.join();
System.out.println("Value of count is :" + p1.counter);
}
}
if I declare the increment function as NON-STATIC function the value of the counter at the end will NOT be 2 million.
on the other hand, it works properly when the increment method is defined as static.
As far as I know there will be only ONE increment function for all the Process objects.. so why do I have to declare it as a static method..?
thanks
Declaring it static will cause the synchronized to lock on the Process.class instance. So all threads running will block on the Object within the increment method. Removing the static will cause each thread to only block on the Thread instance (which in your case there are two).
As a result your counter variable is being incremented in parallel and as noted many times, int incrementing is not thread-safe.
As far as I know there will be only ONE increment function for all the Process objects
There is one increment function for the Process class, but the synchronization is done on the Object and not the method for instance:
class Process{
public synchronized void increment() { counter++; }
}
Is equivallent to:
class Process{
public void increment() {
synchronized(this){
counter++;
}
}
Edit: To answer Rouki's question.
class Process{
public static synchronized void increment() { counter++; }
}
Is equivallent to
class Process{
public void increment() {
synchronized(Process.class){
counter++;
}
}
You may want to replace your int counter with an AtomicInteger counter - this way you can remove the synchronized keyword from the method, and it shouldn't matter if the method is a static or instance method.

Thread output inconsistent even when using synchronized keyword

I am very new to threads. I wrote a code and expected my output as 20000 consistently. But that's not the case. Please find the code below:
class Runner4 implements Runnable {
static int count = 0;
public synchronized void increase() {
count++;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
increase();
}
}
}
public class threading4 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runner4());
t1.start();
Thread t2 = new Thread(new Runner4());
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Runner4.count);
}
}
Any explanation?
Thanks!!
You are synchronizing on two different objects in your code (corresponding to the two objects you created). As such, there is no protection of the shared static variable, and you get unpredictable results. Basically, there is no effective synchronization going on in your program. You can fix this with a simple modification.
Change:
public synchronized void increase(){
count++;
}
To:
public void increase(){
synchronized(Runner4.class) {
count++;
}
}
Note that I am not saying this is the best way to accomplish this kind of synchronization - but the important take-away is that, if you are modifying a class level variable, you need class level synchronization as well.
Your code would work if count was not static.
public synchronized void increase() {
// method body
}
is equivalent to
public void increase() {
synchronized(this) {
// method body
}
}
Since count is static, both t1 and t2 are accessing it with different locks, resulting in non-deterministic behavior. Either make Runner4.increase synchronize on a common lock (Runner4.class or a private static lock object would work just fine), or make count non-static.
The way you're trying to achieve what you want is is not really the best way.
A better way to do it is define a class called Counter, as the following:
public class Counter
{
int count;
public Counter()
{
count = 0;
}
public synchronized void increase() {
count++;
}
public int getCount()
{
return count;
}
}
The class has the methods of increasing the counter and getting it.
What you need to do now is have a Counter object to be shared by two threads that call the increase() method. So your thread class would look like this:
class Runner4 extends Thread {
Counter count;
public Runner4(Counter c)
{
count = c;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
count.increase();
}
}
}
Notice that the class takes a Counter object and calls the increase method. Also the class extends Thread instead of implementing Runnable. There is really no much difference, it's just now your Runner4 can use Thread class methods.
From your main defines a Counter object and two Runner4 threads, and then pass the Counter object to each one of them:
public static void main(String[] args) {
Counter count = new Counter();
Thread t1 = new Runner4(count);
t1.start();
Thread t2 = new Runner4(count);
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count.getCount());
}

Categories

Resources