Synchronized static в Java
Last updated: 6 мая 2025 г.synchronized static
(блокировка на уровне класса), а просто synchronized
(блокировка на уровне объекта).
В коде ниже у нас уже будут 2 объекта ресурса одного класса. В них уже будет synchronized static
блок.
В отличии от synchronized, блок synchronized static распространяется на все объекты одного класса.
То есть если поток дошел до synchronized static в одном объекте класса, то он блокирует этот кусок кода не только для других потоков, которые доходят до этого synchronized static в этом же объекте, а и для тех потоков, которые доходят до этого synchronized static в другом объекте того же класса, что и первый объект.
Пример программы:
1public class StaticSinchExample {
2 public static void main(String[] args) {
3 // объект ресурса номер 1
4 CommonResource commonResource1 = new CommonResource();
5 // объект ресурса номер 2
6 CommonResource commonResource2 = new CommonResource();
7 for (int i = 1; i < 6; i++) {
8 // запускаем 5 потоков, передаем в каждый из них
9 // первый ресурс, общий для 5 потоков
10 Thread t1 = new Thread(new CountThread(commonResource1));
11 // запускаем 5 потоков, передаем в каждый из них
12 // второй ресурс, общий для 5 потоков
13 Thread t2 = new Thread(new CountThread(commonResource2));
14 t1.setName("Thread t1_" + i);
15 t2.setName("Thread t2_" + i);
16 t1.start();
17 t2.start();
18 }
19 // То есть, если один из 10 запускаемых выше потоков
20 // дойдет до блока synchronized static в каком-либо
21 // из объектов ресурсов, будь то commonResource1
22 // или commonResource2, то блок synchronized static
23 // будет заблокирован для всех остальных потоков
24 // во всех объектах ресурсов.
25 }
26}
27
28class CommonResource {
29 int x;
30 static int x1;
31
32 synchronized static void incrementstatic() {
33 // Верхнюю строчку можно было бы переписать
34 // как synchronized (CommonResource.class) –
35 // блокирует для остальных потоков блок кода
36 // класса, а не блок кода конкретного объекта.
37 x1 = 1;
38 for (int i = 1; i < 5; i++) {
39 System.out.printf("Static %s %d \n",
40 Thread.currentThread().getName(), x1);
41 x1++;
42 try {
43 Thread.sleep(1100);
44 } catch (InterruptedException e) {}
45 }
46 }
47
48 synchronized void increment() {
49 // Верхнюю строчку можно было бы переписать
50 // как synchronized (this) – блокирует для
51 // остальных потоков блок кода
52 // конкретного объекта.
53 x = 1;
54 for (int i = 1; i < 5; i++) {
55 System.out.printf("%s %d \n",
56 Thread.currentThread().getName(), x);
57 x++;
58 try {
59 Thread.sleep(100);
60 } catch (InterruptedException e) {}
61 }
62 }
63}
64
65class CountThread implements Runnable {
66 CommonResource res;
67
68 CountThread(CommonResource res) {
69 this.res = res;
70 }
71
72 public void run() {
73 CommonResource.incrementstatic();
74 }
75}
Вывод:

Как видно, все 10 потоков выводятся по очереди.
То есть 4 значения одного потока из 10 потоков, потом 4 значения другого из 10 потоков и так до десятого потока.
Что значит, что блокировка synchronized static распространяется на все объекты ресурсов.
Детали о разнице synchronized static и просто synchronized.
synchronized static
(на уровне класса) и просто synchronized
(на уровне объекта) это ДВЕ РАЗНЫЕ БЛОКИРОВКИ. Могут выполняться параллельно друг другу.
Один sinchronized метод блокирует доступ и к другим synchronized методам в объекте. То есть если поток зашел в один synchronized метод объекта, то заблокирован для других потоков не только этот synchronized метод в этом объекте, заблокированы для других потоков и другие synchronized методы в этом объекте пока поток не покинет synchronized метод в объекте.
Если же один поток зашел в просто synchronized метод (не static) в объекте, то другие потоки могут спокойно заходить в synchronized static методы в этом объекте не дожидаясь пока поток, который зашел в просто synchronized выйдет оттуда.
То есть просто syncronized метод в объекте и synchronized static метод в этом объекте могут выполняться параллельно друг другу.
Пример программы:
1public class StaticSinchExample2 {
2 public static void main(String[] args) {
3 //Объект ресурса
4 CommonResource commonResource = new CommonResource();
5 for (int i = 1; i < 6; i++) {
6 //запускаем 5 потоков и передаем
7 //в каждый из них ресурс общий для потоков
8 Thread t = new Thread(new CountThread(commonResource));
9 t.setName("Thread " + i);
10 t.start();
11 }
12 }
13}
14
15class CommonResource {
16 int x;
17 static int x1;
18
19 synchronized void increment() {
20 x = 1;
21 for (int i = 1; i < 5; i++) {
22 System.out.printf("%s %d \n", Thread.currentThread().getName(), x);
23 x++;
24 try {
25 Thread.sleep(250);
26 } catch (InterruptedException e) {}
27 }
28 }
29
30 synchronized static void incrementstatic() {
31 x1 = 1;
32 for (int i = 1; i < 5; i++) {
33 System.out.printf("Static %s %d \n", Thread.currentThread().getName(), x1);
34 x1++;
35 try {
36 Thread.sleep(700);
37 } catch (InterruptedException e) {}
38 }
39 }
40}
41
42//Код synchronized метода и synchronized static метода
43//не должны пересекаться так как блоки synchronized static
44//и просто synchronized могут выполняться параллельно,
45//а если они могут выполняться параллельно значит
46//они не синхронизированы между собой.
47
48class CountThread implements Runnable {
49 CommonResource res;
50
51 CountThread(CommonResource res) {
52 this.res = res;
53 }
54
55 public void run() {
56 //один поток может выполнять incrementstatic метод
57 CommonResource.incrementstatic();
58 //другой поток может в это же время
59 //параллельно выполнять increment
60 res.increment();
61 }
62}
Вывод:

Как видно, после выхода Thread 1 из incrementstatic метода Thread 1 входит в increment метод и выполнение этого метода, как видно, происходит параллельно потоку Thread 5, который зашел в incrementstatic метод как только из него вышел Thread 1.
То есть очевидно synchronized static блок и synchronized блок выполняются параллельно друг другу.
Следующие уроки
Синхронизация с помощью Wait/Notify
9
мин.
Метод yield в Java
10
мин.
Semaphore в Java
10
мин.