Inconsistent results with java threads

I have a thread class that implements runnable and int counter as an instance variable. Two synchronized add and sub methods. When I run my test class, it somehow prints the wrong results once every couple of times. As far as I understand, when the method is synchronized, the whole object will be blocked for access by other threads, with this logic every time we get the same results? Some like it is not. Did I miss something?

My machine is Windows 7, 64 bit.

public class ThreadClass implements Runnable { int counter = 0; @Override public void run() { add(); sub(); } public synchronized void add() { System.out.println("ADD counter" + (counter = counter + 1)); } public synchronized void sub() { System.out.println("SUB counter" + (counter = counter - 1)); } } 

Testclass

 public class ThreadTest { public static void main(String args[]) { ThreadClass tc = new ThreadClass(); Thread tc0 = new Thread(tc); tc0.start(); tc0.setPriority(Thread.MAX_PRIORITY); Thread tc1 = new Thread(tc); tc1.start(); tc1.setPriority(Thread.NORM_PRIORITY); Thread tc2 = new Thread(tc); tc2.start(); tc2.setPriority(Thread.MIN_PRIORITY); } } 

results

 ADD counter1 ADD counter2 SUB counter1 SUB counter0 ADD counter1 SUB counter0 

Note. You may need to perform several runs to create this inconsistency.

+6
source share
3 answers

Synchronization does mean that all threads block waiting to get a lock before they can enter a synchronized block. Only one thread can have an object lock, so only one thread can be in the add() or sub() methods.

However, this does not mean anything else about streamlining. You start three threads - the only guarantee is that they will not stomp on each other, while running the add or sub methods. Topic 1 can call add() , then thread 3 can call add() , then thread 2 can call add() , then all of them can call sub() . Or they could all call add() , and then sub() each. Or any mix is ​​the only requirement that each thread calls add() before it calls sub() , and that neither of the two threads ever calls add() or sub() , while another thread is in this method.

In addition, in some cases, this may be a bad form for synchronizing with this , since it is publicly available - it often prefers to use a closed, closed Object to block, so that no other callers can take your lock and violate any blocking strategies that you have developed.

+3
source

Your results look right.

During the execution of methods, an exclusive lock on the object is created, but between calls to add() and sub() threads can alternate freely.

If you ended up with 0 after all the threads have started, none of them have overwritten eathother, and access to counter been synchronized.

If you want counter go from 0 to 1 sequentially and never hit 2 , then do the following (which will lead to synchronization redundancy at the method level if no other classes are involved):

 @Override public void run() { synchronize(this) { add(); sub(); } } 

However, this makes the whole thread useless, since you can do this in a single-threaded loop.

+5
source

There is nothing wrong with any set of results. They both fit perfectly with what your code does. The execution of the order of several threads is not guaranteed.

Your synchronized methods guarantee you get reliable results - each add call actually adds one and each sub call actually subtracts one. Without them, you can get a final result other than zero.

+2
source

Source: https://habr.com/ru/post/905665/


All Articles