Java multithreading not thread-safe using synchronized - java

A simple multithreading test with synchronization. I thought if it was "synchronized," other threads would wait. What am I missing?
public class MultithreadingCounter implements Runnable {
static int count = 0;
public static void main(String[] args) {
int numThreads = 4;
Thread[] threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++)
threads[i] = new Thread(new MultithreadingCounter(), i + "");
for (int i = 0; i < numThreads; i++)
threads[i].start();
for (int i = 0; i < numThreads; i++)
try {
threads[i].join();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run() {
increment();
}
public synchronized void increment(){
System.out.print(Thread.currentThread().getName() + ": " + count + "\t");
count++; // if I put this first or increment it directly in the print line, it works fine.
}
}
I thought this would display something like:
0: 1 2: 0 1: 2 3: 3
But its actual output:
0: 0 2: 0 1: 0 3: 3
and other variations like this. It should display each increment (i.e. 0,1,2,3) not in order...

Your synchronized keyword is on an instance method. No two threads can execute this method of one of your thread objects at the same time. But, that is not what your code does. Each thread executes the method on its own instance. The synchronization does not do what you seem to intend. If it were a static method, it would.

Your increment method should be static:
public static synchronized void increment() {
Right now, each object is synchronized on that individual instance, but since count is a static variable, you should be synchronizing on the Class object itself.

when synchronized keyword is used before a method, it ensures that that method can be executed by only one thread at a time with respect to that object only. It does not ensure thread safety from other objects.

Related

Threads changing the same Variable wont synchronize [duplicate]

This question already has answers here:
Thread safety in java multithreading
(3 answers)
Difference between volatile and synchronized in Java
(4 answers)
Closed 1 year ago.
My problem is that the code should increment a 1000 times and then output it. But sometimes a isn't 1000 at the end.
public class Counter extends Thread {
private static Integer a = 0;
public void run() {
for (int i = 0; i < 100; i++) {
a++;
}
}
public static void main(String[] args) {
Counter[] ca = new Counter[10];
for (int i = 0; i < 10; i++) {
ca[i] = new Counter();
ca[i].start();
}
for (Counter c : ca) {
try {
c.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(a);
}
This code is the original code that is obviously not going to work because I have multiple Threads accessing the variable a. I've tried putting a synchronized(this) around a++; and marking a as volatile but I still sometimes get a false Result. The only way I've found to make it work reliably it to put join() into the for loop, but that kind of defeats the point of using Threads in the first place.
Any help is appreciated.
There are several problems in the code you posted, and all them a reported in the comments to your qestion.
I try to show the major ones:
Variable a is Integer which is immutable, this means that a++ really means create a new Ineger instance containing the old value plus 1.
the variable a is updated by multiple threads concurrenlty without synchonizazion, this means that the operation a=a+1 canbe split in read a, increment a; if two or more thread read a at the same time the the increment by one the same value
Here is a modified version that uses a Lock to synchronize access to the resource. The main scope of this code is to show that the access to a must be synchronixed between thread; in order to get a "clean design" you must refactor/change a lot of other things.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SyncProblem {
private static int a=0;
private static class IncThread extends Thread {
private Lock lock;
public IncThread(Lock lock) {
this.lock=lock;
}
public void run() {
lock.lock();
try {
for (int i = 0; i < 100; i++) {
a++;
}
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
Lock lock= new ReentrantLock();
IncThread[] ca = new IncThread[10];
for (int i = 0; i < 10; i++) {
ca[i] = new IncThread(lock);
ca[i].start();
}
for (IncThread c : ca) {
try {
c.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(a);
}
}

Adding numbers using multiple threads in java

I am having trouble figuring out what my code is doing as this is my first time coding using multiple threads. To start off, in attempt to learn this type of programming I decided to write a miniature program that uses 8 threads to sum a number. However, no matter what I do it seems as if my program never stops when count = 10, it continues onward. I am using 8 threads as I planned on expanding my program to do large calculations. However, these threads are not correlating at all. They are going way past 10. I have used a synchronized method. I have tried a lock. I have tried implementing both at the same time. No matter what, it appears as if the threads still calculate past 10. See below for my current code.
public class calculator implements Runnable {
static int counter = 0;
static int sum = 0;
private synchronized static int getAndIncrement()
{
// System.out.println("counter is : " + counter);
int temp = counter;
counter = counter + 1;
System.out.println("counter is now : " + counter);
return temp;
}
private synchronized void addToSum(int value)
{
// System.out.println("sum : " + sum + " value: " + value);
sum += value;
}
#Override
public void run()
{
// TODO Auto-generated method stub
while(counter < 10)
{
int tempVal = getAndIncrement();
System.out.println("temp val : " + tempVal);
addToSum(tempVal);
// System.out.println("sum is now : " + sum);
}
}
}
This is my main method:
public static void main(String[] args)
{
calculator[] calc = new calculator[8];
Thread[] thread = new Thread[8];
final long startTime = System.currentTimeMillis();
for(int i = 0; i < 8; i++)
{
calc[i] = new calculator();
thread[i] = new Thread(calc[i]);
thread[i].start();
}
while(thread[0].isAlive() ||thread[1].isAlive() || thread[2].isAlive() || thread[3].isAlive() || thread[4].isAlive() || thread[5].isAlive() || thread[6].isAlive() || thread[7].isAlive())
{}
final long endTime = System.currentTimeMillis();
System.out.println(calculator.sum);
System.out.println("Execution time : " + (startTime - endTime));
}
I appreciate the help!
The synchronized keyword takes the object
lock. This means that two methods that are synchronized cannot execute on the same object. They will, however, execute concurrently on invocation on 2 different objects.
In your example, your code had 8 objects of calculator. The synchronized methods do not help you. Each thread uses it's separate object. You can completely remove the synchronized keyword, and your code will be semantically equivalent.
To avoid this, use the atomic version of the objects (AtomicInt) or lock on the objects themselves: synchronized(counter){...} but for this to work you will have to change the type to Integer.
I've just tested your sample and found the addToSum method doesn't work as expected here with heavy multi-thread, even if synchronized keyword is present.
Here, as sum variable is static, the method can be made static too.
After adding the static keyword, the behavior is as expected:
private static synchronized void addToSum(int value)
{
sum += value;
}
Here a simple test (addToSum replaced by incSum for simplicity) :
class IncrementorThread implements Runnable {
private static int sum = 0;
private static synchronized void incSum()
{
sum ++;
}
public void run() {
incSum();
Thread.yield();
}
}
void testIncrementorThread1() {
ExecutorService executorService = Executors.newCachedThreadPool();
//ExecutorService executorService = Executors.newSingleThreadExecutor() // result always ok without needing concurrency precaution
for(int i = 0; i < 5000; i++)
executorService.execute(new IncrementorThread());
executorService.shutdown();
executorService.awaitTermination(4000, TimeUnit.MILLISECONDS);
System.out.println("res = "+IncrementorThread.sum); // must be 5000
}
Result must be 5000, which is not the case if we remove the static keyword from the method incSum()

volatile example (that in JLS8/8.3.1.4 volatile Fields) not work?

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4
Java Language Specification 8/8.3.1.4 volatile Fields
volatile example
Question:
In the example of volatile, I add synchronized keyword to method two() to avoid executing one() during method two().
But I still noticed j is larger than i: why ?
Note:
I use Java HotSpot 1.8.0_112.
If you can not noticed j is larger than i, please set testVolatile()/num to a larger number.
My demo:
public class VolatileDemo {
static volatile int i = 0, j = 0;
static void one() {
i++;
j++;
}
static synchronized void two() {
if (i != j)
System.out.println("i=" + i + " j=" + j);
}
static void testVolatile() {
int num = 5000;
for (int i = 0; i < num; i++) {
new Thread(new Runnable() {
public void run() {
one();
}
}).start();
}
for (int i = 0; i < num; i++) {
new Thread(new Runnable() {
public void run() {
two();
}
}).start();
}
}
public static void main(String[] args) {
testVolatile();
}
}
My result:
i=4996 j=4998
i=4998 j=5000
i=4998 j=5000
....
It's possible and it's described in the link you mentioned. It's at the end of the paragraph.
It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.
So two() method reads i and then j with the exact order as in your code. But there are a cople of one() method calls between that reads which gives the result of (4998, 5000)

multi-threading: thread gets own copy of method, but parameter is shared

I want to confirm my understanding on this -
public class Main {
private static int j = 0;
private int k = 0;
public static void main(String[] args) {
Main obj = new Main();
obj.doProcess();
}
public void doProcess() {
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 4; i++) {
service.submit(new SingleProcessor());
}
}
public static void myStaticMethod() {
System.out.println("my static method");
int i = 0;
i++;
j++;
System.out.println("i " + i);
System.out.println("j " + j);
}
public void myInstanceMethod() {
System.out.println("my instance method");
int i = 0;
i++;
k++;
System.out.println("k " + k);
}
private class SingleProcessor implements Runnable {
#Override
public void run() {
System.out.println("single run starts" + Thread.currentThread().getName());
myStaticMethod();
myInstanceMethod();
}
}
}
When a thread runs, it gets it's own copy of methods, be it static or instance method - any variable created inside these methods are local and specific to that thread. It's like multiple 'instances' of this method are getting executed simultaneously, any variable created inside is not shared (it's local).
However parameters (static or instance) are shared by threads.
So in above example -
i is local and specific to thread.
j is shared.
k is shared.
output -
single run startspool-1-thread-1
single run startspool-1-thread-2
my static method
single run startspool-1-thread-3
my static method
i 1
i 1
j 2
j 2
my instance method
my instance method
k 1
k 2
my static method
i 1
j 3
my instance method
k 3
single run startspool-1-thread-4
my static method
i 1
j 4
my instance method
k 4
Is my understanding 100% correct? Anyone would like to put it in better words?
Thanks.
If I followed correctly-- that should be correct.
Its the basic understanding of stack vs heap. Anything declared on the stack (variables declared in a function) is only available locally. Variables declared on the heap can be access globally or by any function within its scope.
So if you have a thread processing a function all the variables inside the function can only be accessed within that function. BUT if you have a global variable and two threads both threads can access that variable. The catch is that you have to make sure they don't override one another if they write to that variable.
The solution for this is locking a heap variable while one thread is read/writing to it and then unlocking it when its done.
What do you think would happen if you run the code below? You'll see a similar output, but in different order, probably. i is a static variable and is in static scope, j is in method scope, k is an instance variable of Main. Same stuff with threads. Scopes work the same with threads. You should read about inner classes instead.
public class Main {
private static int j = 0;
private int k = 0;
public static void main(String[] args) {
Main obj = new Main();
obj.doProcess();
}
public void doProcess() {
for (int i = 0; i < 4; i++) {
SingleProcessor sp = new SingleProcessor();
sp.run();
}
}
public static void myStaticMethod() {
System.out.println("my static method");
int i = 0;
i++;
j++;
System.out.println("i " + i);
System.out.println("j " + j);
}
public void myInstanceMethod() {
System.out.println("my instance method");
int i = 0;
i++;
k++;
System.out.println("k " + k);
}
private class SingleProcessor implements Runnable {
#Override
public void run() {
System.out.println("single run starts" + Thread.currentThread().getName());
myStaticMethod();
myInstanceMethod();
}
}
}
You're right.
A static variable could be intrepreted as a Singleton in your application, no matter how many Threads you have, they'll always have a reference to the same variable.
As for your instance variable 'k', it only works because your nested class is not static, which means you need an instance of Main to be able to instanciate SingleProcessor. Your instance of SingleProcessor will, under the hood' have a hidden variable referencing you Main instance. It's the same as if you'ld write this:
public class SingleProcessor implements Runnable {
private Main main;
public SingleProcessor(Main main){
this.main = main;
}
#Override
public void run() {
System.out.println("single run starts" + Thread.currentThread().getName());
Main.myStaticMethod();
this.main.myInstanceMethod();
}
}
And give all of your SingleProcessor the same Main instance.
All of this is dangerous, a Thread may acquire a variable the same time another Thread is modifying it. There's alot of advanced topics about Thread safety. For simple types, you can use Atomic variables, se Concurrency package JavaDoc.

Synchronized doesn't help to achieve mutual exclusion

Class C:
class C extends Thread
{
public static int cr;
C(int n)
{
cr = n;
}
public void run()
{
go();
}
synchronized void go()
{
for (int i = 0; i < 10000; i++)
{
cr++;
}
}
}
Class Launch
class Launch
{
public static void main(String args[]) throws InterruptedException
{
C[] c = new C[10];
for (int i = 0; i < 10; i++)
{
c[i] = new C(0);
}
for (int i = 0; i < 10; i++)
{
c[i].start();
}
System.out.println(C.spaces);
}
}
It doesn't give me 100,000, but rather numbers below 100k. Why? I made method go() synchronized, so it should be used by only one thread at a time..? What am I missing?
synchronized void go(){...} means that it is synchronized on current instance (on this). Since this method belongs to your custom Thread class and you are crating 10 threads there exist 10 different this references.
That is one of the reasons it is preferred to not extend Thread class, but to implement Runnable interface and pass instance of this interface to as many threads as you want.
Another problem is that you are printing edited value without waiting for threads to finish.
What you need is creating one instance which will hold value you want to change and invoke synchronized method from only one instance, because as mentioned by default synchronized void method is synchronized on this (current object on which this method is invoked).
class MyTask implements Runnable {
public volatile int counter;
MyTask(int n) {
counter = n;
}
public void run() {
System.out.println(Thread.currentThread().getName()+" entered run");
go();
System.out.println(Thread.currentThread().getName()+" finished run");
}
synchronized void go() {
System.out.println(Thread.currentThread().getName()+" entered go");
for (int i = 0; i < 10000; i++) {
counter++;
}
System.out.println(Thread.currentThread().getName()+" left from go");
}
}
class Luncher {
public static void main(String args[]) throws InterruptedException {
//lets create task we want to execute in parallel
MyTask task = new MyTask(0);
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++)//create thread instances
threads[i] = new Thread(task);
for (int i = 0; i < 10; i++)//start threads
threads[i].start();
for (int i = 0; i < 10; i++)
threads[i].join();//hold main thread to wait till all threads will finish
System.out.println(task.counter);
}
}
with
c[i] = new C(0);
you are creating new instance of c every time
with
synchronized void go()
{
for (int i = 0; i < 10000; i++)
{
cr++;
}
}
you will always get the number less than 10000 i dont know why you are expecting 100,000
Is it a typo mistake i < 10000 where you should have u used 100,000 ?
To answer your last question
I made method go() synchronized, so it should be used by only one thread at a time..?
if only one thread at a time, you don't need synchronized(multithreading concept).
It doesn't give me 100,000, but rather numbers below 100k. Why?
Every thing is working fine but main thread is not waiting for other threads to complete the calculation hence output is random in main thread.
Use Thread#join() so that main thread waits for all the other threads to die before executing the last line of the main thread.
for (int i = 0; i < 10; i++) {
c[i].start();
c[i].join(); // Waits for this thread to die
}
System.out.println(C.cr); // output 100000
It's worth reading How do I pause main() until all other threads have died?

Categories