Увод у синхронизацију на Јави

Синхронизација је функција Јава која ограничава вишеструке нити у покушају истовремено приступају заједничким ресурсима. Овде се дељени ресурси односе на садржај спољне датотеке, варијабле класе или записе базе података.

Синхронизација се широко користи у вишечланом програмирању. „Синхронизовано“ је кључна реч која вашем коду пружа могућност да дозволи да само један нит ради на њему без уплитања било које друге нити у том периоду.

Зашто нам треба Јава синхронизација?

  • Јава је вишеслојни програмски језик. То значи да се две или више нити могу покренути истовремено према испуњењу задатка. Када се нити покрећу истовремено, велике су шансе да ће се догодити сценарио где би ваш код могао да пружи неочекиване исходе.
  • Можда се питате да ако мултитхреадинг може изазвати погрешне излазе, зашто се онда то сматра важном особином у Јави?
  • Мултитхреадинг убрзава ваш код покретањем више нити паралелно и на тај начин смањује време извршења кода и пружа високу перформансу. Међутим, коришћење мултитхреадинг окружења доводи до нетачних резултата због стања обично познатог као тркачки услов.

Шта је тркачко стање?

Када се две или више нити покреће паралелно, они имају приступ и измењују заједничке ресурсе у том тренутку. Секвенце у којима се нити извршавају одлучују алгоритам за распоређивање нити.

Због тога се не може предвидјети редослед којим ће се извршавати нити јер њиме управља искључиво планер нити. Ово утиче на излаз кода и резултира недоследним излазима. Пошто се више нити креће једни са другима да би довршили операцију, тај се услов назива "тркачким условима".

На пример, размотримо следећи код:

Class Modify:
package JavaConcepts;
public class Modify implements Runnable(
private int myVar=0;
public int getMyVar() (
return myVar;
)
public void setMyVar(int myVar) (
this.myVar = myVar;
)
public void increment() (
myVar++;
)
@Override
public void run() (
// TODO Auto-generated method stub
this.increment();
System.out.println("Current thread being executed "+ Thread.currentThread().getName() + "Current Thread value " + this.getMyVar());
)
)
Class RaceCondition:
package JavaConcepts;
public class RaceCondition (
public static void main(String() args) (
Modify mObj = new Modify();
Thread t1 = new Thread(mObj, "thread 1");
Thread t2 = new Thread(mObj, "thread 2");
Thread t3 = new Thread(mObj, "thread 3");
t1.start();
t2.start();
t3.start();
)
)

На узастопном извођењу горњег кода, резултати ће бити следећи:

Оурпут1:

Тренутни конац се изводи нит 1 Тренутна вредност навоја 3

Тренутни конац се изводи нит 3 Тренутна вредност навоја 2

Тренутна нит се извршава нит 2 Тренутна вредност навоја 3

Излаз2:

Тренутни конац се изводи нит 3 Тренутна вредност навоја 3

Тренутна нит се извршава нит 2 Тренутна вредност навоја 3

Тренутни конац се изводи нит 1 Тренутна вредност навоја 3

Излаз3:

Тренутна нит се извршава нит 2 Тренутна вредност навоја 3

Тренутни конац се изводи нит 1 Тренутна вредност навоја 3

Тренутни конац се изводи нит 3 Тренутна вредност навоја 3

Излаз4:

Тренутна нит се извршава нит 1 Тренутна вредност навоја 2

Тренутни конац се изводи нит 3 Тренутна вредност навоја 3

Тренутна нит се извршава нит 2 Тренутна вредност навоја 2

  • Из горњег примера можете закључити да се нити извршавају насумично и да је вредност нетачна. Према нашој логици, вредност треба повећати за 1. Међутим, овде је вредност излаза у већини случајева 3, а у неколико случајева је 2.
  • Овде је „миВар“ променљива заједнички ресурс на којем се извршавају више нити. Нити истовремено приступају и мењају вредност „миВар“. Да видимо шта ће се догодити ако коментаришемо друга два теме.

Излаз у овом случају је:

Тренутни конац који се изводи нит 1 Тренутна вриједност навоја 1

То значи да када се покреће једна нит, излаз је онакав какав се и очекивало. Међутим, када се покреће више нити, вриједност се мијења сваком нити. Стога је потребно ограничити број нити који раде на заједничком ресурсу на једну нит. Ово се постиже синхронизацијом.

Разумевање шта је синхронизација у Јави

  • Синхронизација у Јави се постиже уз помоћ кључне речи „синхронизовано“. Ова кључна реч може да се користи за методе или блокове или објекте, али не може се користити са класама и променљивим. Синхронизовани део кода омогућава само једној нити да му приступи и модификује у датом тренутку.
  • Међутим, синхронизовани део кода утиче на перформансе кода јер повећава време чекања других нити који покушавају да му приступе. Дакле, део кода треба синхронизовати само када постоји шанса да се догоди неко стање трке. Ако ни један, то не треба избегавати.

Како синхронизација у Јави функционише интерно?

  • Интерна синхронизација у Јави реализована је уз помоћ закључавања (познатог и као монитор). Сваки Јава објект има сопствено закључавање. У синхронизованом блоку кода, нит мора да стекне браву пре него што буде у могућности да изврши тај одређени блок кода. Једном када нит добије закључавање, може извршити тај део кода.
  • По завршетку извршења, брава се аутоматски ослобађа. Ако је потребно да други навој ради на синхронизованом коду, чека тренутни навој који ради на њему да ослободи браву. За овај поступак добијања и ослобађања брава интерно се брине Јава виртуелна машина. Програм није одговоран за прикупљање и ослобађање браве од стране нити. Преостале нити могу, међутим, истовремено извршавати било који други несинхронизовани део кода.

Синхронизујмо наш претходни пример синхронизацијом кода унутар методе покретања помоћу синхронизованог блока у класи „Измени“, као што следи:

Class Modify:
package JavaConcepts;
public class Modify implements Runnable(
private int myVar=0;
public int getMyVar() (
return myVar;
)
public void setMyVar(int myVar) (
this.myVar = myVar;
)
public void increment() (
myVar++;
)
@Override
public void run() (
// TODO Auto-generated method stub
synchronized(this) (
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
)
)
)

Код за класу РацеЦондитион остаје исти. Сада када покрећете код, излаз је следећи:

Излаз1:

Тренутни конац који се изводи нит 1 Тренутна вриједност навоја 1

Тренутна нит се извршава нит 2 Тренутна вредност навоја 2

Тренутни конац који се изводи нит 3 Тренутна вредност навоја 3

Излаз2:

Тренутни конац који се изводи нит 1 Тренутна вриједност навоја 1

Тренутни конац који се изводи нит 3 Тренутна вредност навоја 2

Тренутна нит која се изводи нит 2 Тренутна вриједност навоја 3

Примјетите да наш код даје очекивани излаз. Овде свака нит повећава вредност за 1 за променљиву „миВар“ (у класи „Модифи“).

Напомена: Синхронизација је потребна када на истом објекту дјелује више нити. Ако више нити функционише на више објеката, тада синхронизација није потребна.

На пример, модификујмо код у класи „РацеЦондитион“ као ниже и радимо са претходно несинхронизованом класом „Модифи“.

package JavaConcepts;
public class RaceCondition (
public static void main(String() args) (
Modify mObj = new Modify();
Modify mObj1 = new Modify();
Modify mObj2 = new Modify();
Thread t1 = new Thread(mObj, "thread 1");
Thread t2 = new Thread(mObj1, "thread 2");
Thread t3 = new Thread(mObj2, "thread 3");
t1.start();
t2.start();
t3.start();
)
)

Излаз:

Тренутни конац који се изводи нит 1 Тренутна вриједност навоја 1

Тренутна нит која се изводи нит 2 Тренутна вриједност навоја 1

Тренутна нит која се изводи нит 3 Тренутна вредност навоја 1

Врсте синхронизације на Јави:

Постоје две врсте синхронизације навоја, једна међусобно искључива, а друга међусобна комуникација.

1.Узајамно искључиви

  • Синхронизовани метод.
  • Статичка синхронизована метода
  • Синхронизовани блок.

2. Координација навоја (комуникација између нити у јави)

Међусобно искључују:

  • У овом случају, нити добивају закључавање прије рада на објекту, избјегавајући тако да раде с објектима за које су њихове вриједности манипулирале другим нитима.
  • То се може постићи на три начина:

ја. Синхронизовани метод: Можемо да користимо кључну реч „синхронизовано“ за методу, чинећи је синхронизованом методом. Свака нит која се позива на синхронизовану методу добиће закључавање за тај објект и отпустити га након завршетка његове операције. У горњем примеру можемо начин „рун ()“ учинити синхронизованим коришћењем кључне речи „синхронизовано“ после модификатора приступа.

@Override
public synchronized void run() (
// TODO Auto-generated method stub
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
)

Излаз за овај случај ће бити:

Тренутни конац који се изводи нит 1 Тренутна вриједност навоја 1

Тренутни конац који се изводи нит 3 Тренутна вредност навоја 2

Тренутна нит која се изводи нит 2 Тренутна вриједност навоја 3

ии. Статичка синхронизована метода: За синхронизацију статичких метода потребно је стећи закључавање на нивоу класе. Након што нит добије закључавање нивоа класе тек тада ће моћи да изврши статичку методу. Иако нит држи закључавање нивоа класе, ниједан други нит не може извршити било који други статички синхронизовани метод те класе. Међутим, остале нити могу да изврше било коју другу редовну методу или редовну статичку методу или чак несталну синхронизовану методу те класе.

На пример, размотримо нашу класу „Модифи“ и променимо је претварањем наше методе „прираста“ у статички синхронизовани метод. Измене кода су као што следи:

package JavaConcepts;
public class Modify implements Runnable(
private static int myVar=0;
public int getMyVar() (
return myVar;
)
public void setMyVar(int myVar) (
this.myVar = myVar;
)
public static synchronized void increment() (
myVar++;
System.out.println("Current thread being executed " + Thread.currentThread().getName() + " Current Thread value " + myVar);
)
@Override
public void run() (
// TODO Auto-generated method stub
increment();
)
)

иии. Синхронизовани блок: Један од главних недостатака синхронизоване методе је тај што повећава вријеме чекања нити утјече на рад кода. Стога, да бисте могли да синхронизујете само тражене редове кода уместо целокупне методе, потребно је користити синхронизовани блок. Коришћење синхронизованог блока смањује време чекања нити и такође побољшава перформансе. У претходном примеру смо већ користили синхронизовани блок истовремено синхронизујући наш код.

Пример:
public void run() (
// TODO Auto-generated method stub
synchronized(this) (
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
)
)

Координација навоја:

За синхронизоване нити, комуникација између нити је важан задатак. Уграђене методе које помажу у остваривању међу-нитне комуникације за синхронизовани код су:

  • чекати()
  • нотифи ()
  • нотифиАлл ()

Напомена: Ове методе припадају објектној класи, а не класи нити. Да би нит могла позивати ове методе на објект, требало би да држи браву на том објекту. Такође, ове методе узрокују да нит ослободи закључавање на објекту на који се позива.

ваит (): нит за позивање методе ваит (), ослобађа закључавање објекта и прелази у стање чекања. Има две методе преоптерећења:

  • јавно финално неисправно чекање () избацује ИнтерруптедЕкцептион
  • јавно коначно неисправно чекање (дуготрајно истекло) баца ИнтерруптедЕкцептион
  • јавно финално неисправно чекање (дуготрајно време, инт нанос) избацује ИнтерруптедЕкцептион

нотифи (): нит шаље сигнал на другу нит у стању чекања користећи методу нотифи (). Обавештење шаље само једној нити да би овај низ могао да настави са извршењем. Који ће низ примити обавештење између свих нити у стању чекања зависи од Јава Виртуал Мацхине.

  • јавно коначно неважеће обавештење ()

нотифиАлл (): Када се нит позива на нотифиАлл () методу, обавјештава се свака нит у стању чекања. Ове нити ће се извршавати једна за другом на основу редоследа који је одлучила Јава виртуелна машина.

  • јавно коначно неважеће обавештењеАлл ()

Закључак

У овом смо чланку видјели како рад у окружењу с више навоја може довести до неусклађености података због стања трке. Како нам синхронизација помаже да то превазиђемо ограничавањем једне нити за рад на заједничком ресурсу у исто време. Такође како синхронизоване нити комуницирају једна са другом.

Препоручени чланци:

Ово је водич за шта је Синхронизација у Јави ?. Овде смо разговарали о увођењу, разумевању, потреби, раду и врстама синхронизације са неким узорком кода. Можете и да прођете кроз друге наше предложене чланке да бисте сазнали више -

  1. Серијализација у Јави
  2. Шта је генерика у Јави?
  3. Шта је АПИ на Јави?
  4. Шта је бинарно дрво на Јави?
  5. Примери и како генеричари раде у Ц #

Категорија: