Here such not difficult piece of code

public class Solution { public static void main(String[] args) throws InterruptedException { Counter counter1 = new Counter(); Counter counter2 = new Counter(); Counter counter3 = new Counter(); Counter counter4 = new Counter(); counter1.start(); counter2.start(); counter3.start(); counter4.start(); counter1.join(); counter2.join(); counter3.join(); counter4.join(); for (int i = 1; i <= 100; i++) { if (values[i] != 1) { System.out.println("Массив values содержит элементы неравные 1"); break; } } } public static Integer count = 0; public static int[] values = new int[105]; static { for (int i = 0; i < 105; i++) { values[i] = 0; } } public synchronized static void incrementCount() { count++; } public synchronized static int getCount() { return count; } public static class Counter extends Thread { @Override public void run() { do { ---->>> synchronized (Counter.class) { <<<--- incrementCount(); values[getCount()]++; } try { Thread.sleep(1); } catch (InterruptedException e) { } } while (getCount() < 100); } } } 

So when I write synchronized (Counter.class) shows correctly when it was like this synchronized (this) said that it was not correct ...

What is the difference? I understand that the parameter is a locker, but what difference does it make which locker is transmitted in this example? He thinks he is the same ...

    2 answers 2

    synchronized (this) is an object-level ( specific class instance ) lock.

    synchronized (Counter.class) is a lock at the class level (at the level of all existing instances of this class).

    Let two threads work with different instances, then:

    • in the synchronized (this) block, both threads can work simultaneously;
    • in a synchronized (Counter.class) block synchronized (Counter.class) , only one stream can work, the second will wait for the first one to exit from this block.

    Let's look at a specific example:

    Option number one:

     class Example { void print() { synchronized (this) { for (int i=0; i<3; i++) { System.out.println(Thread.currentThread().getName() + ": i = " + i); } } } } 

    Option number two:

     class Example { void print() { synchronized (Example.class) { for (int i=0; i<3; i++) { System.out.println(Thread.currentThread().getName() + ": i = " + i); } } } } 

    Creating and running threads:

     Example example1 = new Example(); Example example2 = new Example(); Thread t1 = new Thread(){ public void run(){ example1.print(); } }; t1.setName("First thread"); t1.start(); Thread t2 = new Thread(){ public void run(){ example2.print(); } }; t2.setName("Second thread"); t2.start(); 

    In the first version, we get:

     Second thread: i = 0 First thread: i = 0 Second thread: i = 1 Second thread: i = 2 First thread: i = 1 First thread: i = 2 

    And in the second:

     First thread: i = 0 First thread: i = 1 First thread: i = 2 Second thread: i = 0 Second thread: i = 1 Second thread: i = 2 

    As can be seen from the results, in the first case, the threads are executed asynchronously, and in the second case, one thread waits until another thread leaves the synchronized block.

    • In the first case, as you can see, the execution is asynchronous and I understand that synchronous execution will be if we run the execution of the same object 2 times (say example1 )? Right? - Aleksey Timoshchenko
    • @AlekseyTimoshchenko, Yes. If two threads will manipulate one instance, then they will enter the synchronized block in turn. - post_zeew
    • Thank! Got it. - Aleksey Timoshchenko
    • And here again I have a question. Why should we specify the synchronized method in the Counter class which covers incrementCount(); values[getCount()]++; incrementCount(); values[getCount()]++; if these methods are initially marked as synchronized ? - Aleksey Timoshchenko
    • @AlekseyTimoshchenko, What if the incrementCount() method is called from somewhere else? - post_zeew

    Well then, when you synchronize on a class, then essentially only one such block of code can be executed at a time, regardless of which instance of the object. And when you synchronize on this , it is synchronized on the given instance, i.e. synchronization of this counter does not affect others, so they will be executed, and not wait for the completion of each other's execution.