This question already has answers here:
Synchronization on immutable objects (in java)
(4 answers)
Closed 6 years ago.
I'm new to java and was trying out synchronization with a sample program to add numbers upto 100 using multiThreading. And following is code i was able to come up with. When i test the code it sometimes gives the correct value of 4590 but sometimes doesnt give the correct value. Can anyone point out what i'm doing wrong
class Counter{
Integer counter = 0;
public void increment(int i){
synchronized (counter){
counter += i;
}
}
}
class ObjectTest implements Runnable{
int i;
Counter blah;
public ObjectTest(Counter counter,int i){
blah =counter;
this.i = i;
}
#Override
public void run() {
blah.increment(i);
}
}
public class SyncTest {
public static void main(String args[]) throws InterruptedException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(4,10,60, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());
Counter counter = new Counter();
for (int index = 0; index < 100; index++) {
ObjectTest objectTest = new ObjectTest(counter,index);
executor.execute(objectTest);
}
executor.shutdown();
while (!executor.isTerminated()){
Thread.sleep(1000L);
}
System.out.println(counter.counter);
}
}
You can't synchronize on counter because it's an Integer, which is immutable. Therefore counter += i creates a new Integer object, which is not the same that was synchronized on.
You can make it int counter and have a separate Object lock = new Object();, synchronizing on lock.
Related
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);
}
}
I do not understand why each time I run this code I get different answer ?
Correct answer should be one 98098 two 98099. Anyone have any ideas why this is not working that way ? For example one time answer comes back "one 49047 two 49047" then another time it comes back "one 40072 two 40072". I am so confused at this point and lack any reasonable explanation
public class TestThreads {
public static void main(String[] args){
ThreadOne t1 = new ThreadOne();
ThreadTwo t2 = new ThreadTwo();
Thread one = new Thread(t1);
Thread two = new Thread(t2);
one.start();
two.start();
}
}
class ThreadOne implements Runnable {
Accum a = Accum.getAccum();
public void run(){
for(int x = 0; x < 98; x++){
a.updateCounter(1000);
try{
Thread.sleep(50);
}catch(InterruptedException ex){
}
}
System.out.println("one " + a.getCount());
}
}
class ThreadTwo implements Runnable {
Accum a = Accum.getAccum();
public void run(){
for(int x = 0; x < 99; x++){
a.updateCounter(1);
try{
Thread.sleep(50);
}catch(InterruptedException ex){
}
}
System.out.println("two " + a.getCount());
}
}
class Accum {
private static Accum a = new Accum();
public static Accum getAccum(){
return a;
}
private int counter = 0;
public int getCount(){
return counter;
}
public void updateCounter(int add){
counter += add;
}
private Accum(){ }
}
As you have two threads updating the same data without thread safety, one thread easily overwrites the value set by the other one.
Each thread works on it's own thread cached value. e.g.
Thread 1 adds 1 one hundred times. It has the value 100
Thread 2 adds 1000 one hundred times. It has the value 100000
At this point, the one value is chosen. say it's thread 1's value.
Thread 1 adds 1 one hundred times. It has the value 200
Thread 2 adds 1000 one hundred times. It has the value 100100
This time, thread 2's value is chosen.
In the end only half the updates on average are retained as the value chosen is somewhat random.
You can get to 98099 by declaring the methods in Accum as synchronized.
This will ensure that only one of the threads can access it's information at a time.
As the other answers have pointed out, you are getting unexpected results because there is nothing to stop each thread overwriting what the other had done.
Try this:
class Accum {
private static Accum a = new Accum();
public static synchronized Accum getAccum(){
return a;
}
private int counter = 0;
public synchronized int getCount(){
return counter;
}
public synchronized void updateCounter(int add){
counter += add;
}
private Accum(){ }
}
your problem is this:
private static Accum a = new Accum();
public static Accum getAccum(){
return a;
}
Since its a STATIC there is only one instance shared by all threads. so when you set it in one thread, all threads get the same new value. if you remove the static notifier and instantiate a new object of class Accum for each thread it should work.
This question already has answers here:
Incrementing AtomicInteger in Java in 1000 threads does not generate value 1000 [duplicate]
(2 answers)
Closed 5 years ago.
My expectation was that the program would return the output "1000".
However, every time the program performs a different output occurs.
The increment() method of the Counter class has been synchronized. Would only this be necessary to avoid competing readings?
What would be the correct way to make it count the 1000 increments?
package app;
public class Counter {
private Integer value;
public Counter(int initialValue) {
value = initialValue;
}
public synchronized void increment() {
value = value + 1;
}
public int getValue() {
return value;
}
}
package app;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
Counter contador = new Counter(0);
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i < 1000; i++) {
executor.submit(() -> {
contador.increment();
});
}
System.out.println(contador.getValue());
}
}
Your logic is fine.
The problem is that you print the value of the counter before the threads finished incrementing it.
Change your code to this:
for(int i = 0; i < 1000; i++) {
executor.submit(() -> {
contador.increment();
});
}
executor.shutdown(); //Shut down the executor
//Wait until the threads have stopped. A maximum of 1 minute is more than enough
executor.awaitTermination(1, TimeUnit.MINUTES);
System.out.println(contador.getValue()); //prints 1000
The answer to your question is that you're not waiting for all your Runnables to finish before printing the value of contador.
So sometimes only 20 calls to increment have been done called and sometimes 50 have been done, etc
Edit:
Looking closer, I think you have a potential issue with your thread safety. You've synchronized the increment value. Should the getValue method match?
For example, if Thread A is in the process of incrementing, what should Thread B see when it calls getValue? Should it see the old value, or should it wait until Thread A is done so it gets the latest value?
This is how your main method should look:
public static void main(String[] args) {
Counter contador = new Counter(0);
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i < 1000; i++) {
executor.submit(() -> {
contador.increment();
});
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
}
System.out.println(contador.getValue());
}
public class MyTest {
ArrayList<Integer> array = new ArrayList<>();
public void initialize() {
//....
}
private void editArray(int num) {
// modified the array
}
public void func(int n) {
for (int i = 0; i < n; i++) {
editArray(i);
}
}
}
I hope to execute "editArray" function in the forloop concurrently, which means n threads(call editArray function) can execute concurrently, how can I do that and add a lock for ArrayList array ? I google a lot, most of tutorials just teach how to spawn thread for different objects. What I want is that spawn thread in a single object.
I mainly want to know how to call a function concurrently in java.
Thanks.
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.