В этой главе мы представим синхронизированные ключевые слова. Включаемое содержание включает в себя:
1. Синхронизированный принцип
2. Синхронизированные основные правила
3. Синхронизированный метод и синхронизированный кодовый блок
4. Замок экземпляра и глобальная блокировка
1. Синхронизированный принцип
В Java каждый объект имеет и имеет только одну блокировку синхронизации. Это также означает, что блокировка синхронизации существует на объекте.
Когда мы называем синхронизированный метод объекта, мы получаем блокировку синхронизации объекта. Например, синхронизированный (OBJ) приобретает блокировку синхронизации «объекта OBJ».
Доступ к блокировке синхронизации различными потоками является взаимно эксклюзивным. Другими словами, в определенный момент времени блокировка синхронизации объекта может быть получена только одним потоком! Через блокировки синхронизации мы можем достичь взаимоисключающего доступа к «объектам/методам» в нескольких потоках. Например, теперь есть два потока A и поток B, которые оба получают доступ «синхронная блокировка объекта obj». Предположим, что в какой -то момент резьба А приобретает «блокировку синхронизации OBJ» и выполняет некоторые операции; B может получить только «блокировку синхронизации OBJ», пока не выпустит «синхронную блокировку этого объекта» и может только работать.
2. Синхронизированные основные правила
Мы суммируем основные правила синхронизации в следующие 3 и проиллюстрируем их с помощью примеров.
Статья 1: Когда поток обращается к «синхронизированному методу» или «синхронизированному кодовому блоку» «определенного объекта», другие потоки будут заблокированы от доступа к «синхронизированному методу» или «синхронизированный кодовый блок» «объекта».
Статья 2: Когда поток обращается к «синхронизированному методу» или «синхронизированному кодовому блоку» «определенного объекта», другие потоки все равно могут получить доступ к асинхронизированному кодовому блоку «этот объект».
Статья 3: Когда поток обращается к «синхронизированному методу» или «синхронизированному кодовому блоку» «определенного объекта», другие потоки будут заблокированы от доступа к другим «синхронизированным методам» или «синхронизированный код».
Статья 1
Когда поток обращается к «синхронизированному методу» или «синхронизированному кодовому блоку» «определенного объекта», другие потоки будут заблокированы от доступа к «синхронизированному методу» или «синхронизированный кодовый блок» «объекта».
Ниже приведена демонстрационная программа, соответствующая «синхронизированному кодовому блоку».
Кода -копия выглядит следующим образом:
Класс Мируньируемые орудительные орудия runnable {
@Override
public void run () {
синхронизированный (это) {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName () + "loop" + i);
}
} catch (прерванная экспрессия т.е.) {
}
}
}
}
открытый класс demo1_1 {
public static void main (string [] args) {
Runnable Demo = New Myrunable ();
Поток T1 = новый поток (демонстрация, "T1");
Поток T2 = новый поток (демонстрация, "T2");
t1.start ();
t2.start ();
}
}
Результаты работы:
Кода -копия выглядит следующим образом:
T1 петля 0
T1 петля 1
T1 петля 2
T1 петля 3
T1 петля 4
T2 петля 0
Т2 петля 1
Т2 петля 2
Т2 петля 3
Т2 петля 4
Результаты Описание:
В методе run () существует «синхронизированный (этот) кодовый блок», а T1 и T2 - это потоки, созданные на основе «демонстрационного» запускаемого объекта. Это означает, что мы можем рассматривать это синхронизированным (это) как «демонстрационный объект»; Следовательно, когда работает один поток, другой поток должен ждать, пока «запущенный поток» выпустит «блокировку демо -синхронизации», прежде чем он сможет запустить.
Если вы подтвердите, вы поняли эту проблему. Затем мы изменяем приведенный выше код, а затем запускаем его, чтобы увидеть, каково это результат, и посмотрим, будут ли вы запутаны. Модифицированный исходный код выглядит следующим образом:
Кода -копия выглядит следующим образом:
класс Mythread Extends Thread {
public mythread (string name) {
супер (имя);
}
@Override
public void run () {
синхронизированный (это) {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName () + "loop" + i);
}
} catch (прерванная экспрессия т.е.) {
}
}
}
}
открытый класс demo1_2 {
public static void main (string [] args) {
Thread T1 = New Mythread ("T1");
Поток T2 = New Mythread ("T2");
t1.start ();
t2.start ();
}
}
Описание кода:
Сравнивая Demo1_2 и Demo1_1, мы обнаружили, что класс Mythread в Demo1_2 непосредственно унаследован от потока, а T1 и T2 - это детские потоки Mythread.
К счастью, метод «run () demo1_2» также называется синхронизированным (это), так же как метод «run () demo1_1», также называемый синхронизированным (это)!
Итак, процесс выполнения DEMO1_2 таким же, как DEMO1_1?
Результаты работы:
Кода -копия выглядит следующим образом:
T1 петля 0
T2 петля 0
T1 петля 1
Т2 петля 1
T1 петля 2
Т2 петля 2
T1 петля 3
Т2 петля 3
T1 петля 4
Т2 петля 4
Результаты Описание:
Если этот результат вас совсем не удивляет, то я считаю, что у вас есть более глубокое понимание синхронизации и этого. В противном случае, пожалуйста, продолжайте читать анализ здесь.
Это синхронизированное (это) относится к «объекту текущего класса», то есть текущего объекта, соответствующего классу, где находится синхронизированный (это). Его цель состоит в том, чтобы получить «синхронную блокировку текущего объекта».
Для Demo1_2 это синхронизированное (это) представляет собой объект Mythread, в то время как T1 и T2 являются двумя разными объектами Mythread. Для пары Demo1_1 это синхронизированное (это) представляет собой мирновой объект;
Статья 2
Когда поток обращается к «синхронизированному методу» или «синхронизированному кодовому блоку» «определенного объекта», другие потоки могут по -прежнему получить доступ к асинхронизированному блоку кода «этот объект».
Ниже приведена демонстрационная программа, соответствующая «синхронизированному кодовому блоку».
Кода -копия выглядит следующим образом:
Class Count {
// метод, содержащий блок синхронизированной синхронизации
public void synmethod () {
синхронизированный (это) {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName () + "Синметод петля" + i);
}
} catch (прерванная экспрессия т.е.) {
}
}
}
// асинхронный метод
public void nonsynmethod () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName () + "nonsynmethod loop" + i);
}
} catch (прерванная экспрессия т.е.) {
}
}
}
открытый класс Demo2 {
public static void main (string [] args) {
окончательный счет count = new Count ();
// Создать новый T1, T1 будет вызвать метод Synmethod () «Объекта графа»
Потока T1 = новый поток (
new Runnable () {
@Override
public void run () {
count.synmethod ();
}
}, "T1");
// Создать новый T2, T2 будет вызвать метод nonsynmethod () «Объекта графа»
Потока T2 = новый поток (
new Runnable () {
@Override
public void run () {
count.nonsynmethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
Результаты работы:
Кода -копия выглядит следующим образом:
T1 Synmethod Loop 0
T2 Nonsynmethod Loop 0
T1 Synmethod Loop 1
T2 Nonsynmethod Loop 1
T1 Synmethod Loop 2
T2 Nonsynmethod Loop 2
T1 Synmethod Loop 3
T2 Nonsynmethod Loop 3
T1 Synmethod Loop 4
T2 Nonsynmethod Loop 4
Результаты Описание:
Две новые детские потоки T1 и T2 создаются в основном потоке. T1 вызовет метод Synmethod () объекта Count, который содержит блоки синхронизации; Когда T1 работает, хотя синхронизирован (это) вызывается для получения «блокировки синхронизации счета»;
Статья 3
Когда поток обращается к «синхронизированному методу» или «синхронизированному кодовому блоку» «определенного объекта», будут заблокированы другие потоки к другим «синхронизированным методам» или «синхронизированный код» «объекта».
Мы также будем изменять кузов метода nonsynmethod () в приведенном выше примере с помощью синхронизированного (это). Модифицированный исходный код выглядит следующим образом:
Кода -копия выглядит следующим образом:
Class Count {
// метод, содержащий блок синхронизированной синхронизации
public void synmethod () {
синхронизированный (это) {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName () + "Синметод петля" + i);
}
} catch (прерванная экспрессия т.е.) {
}
}
}
// также содержит метод синхронизированного блока синхронизации
public void nonsynmethod () {
синхронизированный (это) {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName () + "nonsynmethod loop" + i);
}
} catch (прерванная экспрессия т.е.) {
}
}
}
}
открытый класс Demo3 {
public static void main (string [] args) {
окончательный счет count = new Count ();
// Создать новый T1, T1 будет вызвать метод Synmethod () «Объекта графа»
Потока T1 = новый поток (
new Runnable () {
@Override
public void run () {
count.synmethod ();
}
}, "T1");
// Создать новый T2, T2 будет вызвать метод nonsynmethod () «Объекта графа»
Потока T2 = новый поток (
new Runnable () {
@Override
public void run () {
count.nonsynmethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
(Один раз) Результат выполнения:
Кода -копия выглядит следующим образом:
Synmethod (): 11
Synblock (): 3
4. Замок экземпляра и глобальная блокировка
Замок экземпляра-заблокирован на объекте экземпляра. Если класс является синглтоном, то замок также имеет концепцию глобального блокировки.
Синхронизированное ключевое слово соответствует блокировке экземпляра.
Global Lock- этот замок нацелен на класс.
Глобальная блокировка соответствует статическому синхронизированию (или заблокированной на объекте класса или класса загрузчика этого класса).
Существует очень яркий пример «блокировки экземпляра» и «глобального блокировки»:
Кода -копия выглядит следующим образом:
Пульбический класс что -то {
public Synchrinized void issynca () {}
public Synchrinized void issyncb () {}
Публичный статический синхронизированный void csynca () {}
Публичный статический синхронизированный void csyncb () {}
}
Предположим, что -то имеет два случая x и y. Проанализируйте замки, полученные следующими четырьмя наборами выражений.
(01) x.issynca () и x.issyncb ()
(02) x.issynca () и y.issynca ()
(03) x.csynca () и y.csyncb ()
(04) x.issynca () и что -то.csynca ()
(01) не может быть доступен одновременно. Потому что issynca () и issyncb () являются блокировками синхронизации, которые получают доступ к одному и тому же объекту (объект x)!
Кода -копия выглядит следующим образом:
// lockTest2.java исходный код
класс что -то {
публичный синхронизированный void issynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": issynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
публичный синхронизированный void issyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": issyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": csyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
}
открытый класс locktest2 {
Что -то x = новое что -то ();
Что -то y = новое что -то ();
// сравнить (02) x.issynca () с y.issynca ()
private void test2 () {
// Создать новый T21, а T21 вызовет x.issynca ()
Потока T21 = новый поток (
new Runnable () {
@Override
public void run () {
x.issynca ();
}
}, "T21");
// Создать новый T22, а T22 вызовет x.issyncb ()
Потока T22 = новый поток (
new Runnable () {
@Override
public void run () {
y.issynca ();
}
}, "T22");
t21.start ();
T22.Start ();
}
public static void main (string [] args) {
LockTest2 demo = new LockTest2 ();
demo.test2 ();
}
}
Результаты работы:
Кода -копия выглядит следующим образом:
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T12: Issyncb
T12: Issyncb
T12: Issyncb
T12: Issyncb
T12: Issyncb
(02) можно получить одновременно. Поскольку он не доступ к блокировке синхронизации одного и того же объекта, x.issynca () обращается к блокировке синхронизации x, в то время как y.issynca () обращается к блокировке синхронизации y.
Кода -копия выглядит следующим образом:
// lockTest2.java исходный код
класс что -то {
публичный синхронизированный void issynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": issynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
публичный синхронизированный void issyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": issyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": csyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
}
открытый класс locktest2 {
Что -то x = новое что -то ();
Что -то y = новое что -то ();
// сравнить (02) x.issynca () с y.issynca ()
private void test2 () {
// Создать новый T21, а T21 вызовет x.issynca ()
Потока T21 = новый поток (
new Runnable () {
@Override
public void run () {
x.issynca ();
}
}, "T21");
// Создать новый T22, а T22 вызовет x.issyncb ()
Потока T22 = новый поток (
new Runnable () {
@Override
public void run () {
y.issynca ();
}
}, "T22");
t21.start ();
T22.Start ();
}
public static void main (string [] args) {
LockTest2 demo = new LockTest2 ();
demo.test2 ();
}
}
Результаты работы:
Кода -копия выглядит следующим образом:
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
(03) не может быть доступен одновременно. Поскольку csynca () и csyncb () являются статическими типами, x.csynca () эквивалентен чем -то. Issynca (), а y.csyncb () эквивалентен чем -то. спросить в то же время.
Кода -копия выглядит следующим образом:
// locktest3.java исходный код
класс что -то {
публичный синхронизированный void issynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": issynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
публичный синхронизированный void issyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": issyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": csyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
}
открытый класс locktest3 {
Что -то x = новое что -то ();
Что -то y = новое что -то ();
// Сравнение (03) x.csynca () с y.csyncb ()
private void test3 () {
// Создать новый T31, и T31 позвонит x.issynca ()
Потока T31 = новый поток (
new Runnable () {
@Override
public void run () {
x.csynca ();
}
}, "T31");
// Создать новый T32, а T32 вызовет x.issyncb ()
Потока T32 = новый поток (
new Runnable () {
@Override
public void run () {
y.csyncb ();
}
}, "T32");
t31.start ();
T32.Start ();
}
public static void main (string [] args) {
LockTest3 demo = new LockTest3 ();
demo.test3 ();
}
}
Результаты работы:
Кода -копия выглядит следующим образом:
T31: CSYNCA
T31: CSYNCA
T31: CSYNCA
T31: CSYNCA
T31: CSYNCA
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
(04) можно получить одновременно. Поскольку issynca () является методом экземпляра, x.issynca () использует блокировку объекта x; Следовательно, к ним можно получить доступ одновременно.
Кода -копия выглядит следующим образом:
// lockTest4.java исходный код
класс что -то {
публичный синхронизированный void issynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": issynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
публичный синхронизированный void issyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": issyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csynca () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (прерванная экспрессия т.е.) {
}
}
Публичный статический синхронизированный void csyncb () {
пытаться {
для (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (think.currentThread (). GetName ()+": csyncb");
}
} catch (прерванная экспрессия т.е.) {
}
}
}
открытый класс locktest4 {
Что -то x = новое что -то ();
Что -то y = новое что -то ();
// Сравнение (04) x.issynca () с чем -то. Csynca ()
private void test4 () {
// Создать новый T41, и T41 позвонит x.issynca ()
Потока T41 = новый поток (
new Runnable () {
@Override
public void run () {
x.issynca ();
}
}, "T41");
// Создать новый T42, а T42 вызовет x.issyncb ()
Потока T42 = новый поток (
new Runnable () {
@Override
public void run () {
Что -то.csynca ();
}
}, "T42");
t41.start ();
T42.Start ();
}
public static void main (string [] args) {
LockTest4 demo = new LockTest4 ();
demo.test4 ();
}
}
Результаты работы:
Кода -копия выглядит следующим образом:
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA