java synchronized what is thread synchronization java
Овај водич објашњава синхронизацију нити у Јави заједно са сродним концептима као што су Јава Лоцк, Раце Цондитион, Мутек, Јава Волатиле & Деадлоцк у Јави:
У вишенитном окружењу где је укључено више нити, мора доћи до сукоба када више нити истовремено покушава да добије исти ресурс истовремено. Ови сукоби резултирају „тркачким условима“ и тако програм даје неочекиване резултате.
На пример, једну датотеку ажурирају две нити. Ако је једна нит Т1 у процесу ажурирања ове датотеке, реците неку променљиву. Сада, док је ово ажурирање од стране Т1 још увек у току, рецимо да друга нит Т2 такође ажурира исту променљиву. На овај начин ће променљива дати погрешне резултате.
=> Овде погледајте комплетну серију Јава тренинга.
Када је укључено више нити, тим нитима бисмо требали управљати на такав начин да ресурсу може истовремено приступити појединачна нит. У горњем примеру, датотеком којој приступају обе нити треба управљати на такав начин да Т2 не може да приступи датотеци док Т1 не приступи њој.
То се ради на Јави користећи „ Синхронизација нити ”.
Шта ћете научити:
- Синхронизација нити у Јави
- Вишеструки навој без синхронизације
- Вишеструки навој са синхронизацијом
- Закључак
Синхронизација нити у Јави
Како је Јава језик са више навоја, синхронизација нити има велику важност у Јави јер се више нити паралелно извршава у апликацији.
Користимо кључне речи „Синхронизовано“ и „Испарљив“ да би се постигла синхронизација у Јави
Потребна нам је синхронизација када је дељени објекат или ресурс променљив. Ако је ресурс непроменљив, тада ће нити читати ресурс само истовремено или појединачно.
У овом случају не треба да синхронизујемо ресурс. У овом случају ЈВМ то осигурава Јава синхронизовани код извршава се по једном нити .
Већину времена истовремени приступ дељеним ресурсима на Јави може довести до грешака попут „Неусклађеност меморије“ и „сметње нити“. Да бисмо избегли ове грешке, морамо да синхронизујемо дељене ресурсе тако да се приступ тим ресурсима међусобно искључује.
Користимо концепт тзв Монитори за примену синхронизације. Монитору може истовремено да приступи само једна нит. Када нит добије браву, онда можемо рећи да је нит ушла у монитор.
Када се одређеном нити приступа монитору, монитор се закључава, а све остале нити које покушавају да уђу у монитор се суспендују док се нит за приступ не заврши и не ослободи браву.
Убудуће ћемо детаљно разговарати о синхронизацији у Јави у овом упутству. Сада, разговарајмо о неким основним концептима повезаним са синхронизацијом у Јави.
Услови расе у Јави
У окружењу са више нити, када више нити покушава истовремено да приступи дељеном ресурсу за писање, тада се више нити утркује како би завршило приступ ресурсу. Ово доводи до „услова расе“.
Једна ствар коју треба узети у обзир је да нема проблема ако више нити покушава да приступи заједничком ресурсу само за читање. Проблем настаје када више нити истовремено приступа истом ресурсу.
Услови трке настају услед недостатка одговарајуће синхронизације нити у програму. Када правилно синхронизујемо нити тако да ће истовремено само једна нит приступити ресурсу, а услов расе престаје да постоји.
Па, како да откријемо стање расе?
Најбољи начин за откривање стања расе је преглед кодова. Као програмер, требали бисмо темељито прегледати код како бисмо проверили потенцијалне услове трке који би се могли догодити.
Браве / монитори у Јави
Већ смо споменули да користимо мониторе или браве за спровођење синхронизације. Монитор или брава је интерни ентитет и повезан је са свим објектима. Дакле, кад год нит треба да приступи објекту, прво мора да набави браву или монитор свог објекта, ради на објекту, а затим отпусти браву.
Браве у Јави ће изгледати као што је приказано доле:
public class Lock { private boolean isLocked = false; public synchronized void lock() throws InterruptedException { while(isLocked) { wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
Као што је горе приказано, имамо методу лоцк () која закључава инстанцу. Све нити које позивају методу лоцк () биће блокиране све док скупови метода унблоцк () не буду закључани ознаком на фалсе и обавештавају све нити које чекају.
Неке упуте о бравама:
- У Јави сваки објекат има браву или монитор. Овој брави се може приступити помоћу нити.
- Одједном само једна нит може добити овај монитор или закључати.
- Јава програмски језик пружа кључну реч Синхронизовано ’која нам омогућава да синхронизујемо нити тако што ћемо направити блок или метод као Синхронизовани.
- Заједнички ресурси којима нит треба да приступе чувају се под овим синхронизованим блоком / методом.
Мутекси у Јави
Већ смо разговарали о томе да се у вишенитном окружењу могу појавити тркачки услови када више нити покушава истовремено да приступи дељеним ресурсима, а тркачки услови резултирају неочекиваним резултатима.
Део програма који покушава да приступи дељеном ресурсу назива се „Критични одељак“ . Да би се избегла појава тркачких услова, потребно је синхронизовати приступ критичном делу. Синхронизацијом овог критичног одељка осигуравамо да одједном само једна нит може приступити критичном одељку.
Најједноставнији тип синхронизатора је „мутек“. Мутек осигурава да у било којој датој инстанци само једна нит може извршити критични одељак.
Мутекс је сличан концепту монитора или брава о којем смо раније говорили. Ако нит треба да приступи критичном одељку, онда мора да стекне мутекс. Једном када се стекне мутек, нит ће приступити критичном коду секције, а када заврши, ослободиће мутек.
Остале нити које чекају да приступе критичном одељку у међувремену ће бити блокиране. Чим га нит која држи мутек ослободи, друга нит ће ући у критични одељак.
основна питања и одговори на интервју за техничку подршку
Постоји неколико начина на које можемо применити мутек у Јави.
- Коришћење синхронизоване кључне речи
- Коришћење Семапхоре-а
- Коришћење РеентрантЛоцк-а
У овом упутству ћемо разговарати о првом приступу, тј. О синхронизацији. Преостала два приступа - Семапхоре и РеентрантЛоцк биће размотрени у следећем водичу у којем ћемо разговарати о истовременом јава пакету.
Синхронизована кључна реч
Јава нуди кључну реч „Синхронизовано“ која се у програму може користити за обележавање критичног одељка. Критични одељак може бити блок кода или комплетна метода. Дакле, само једна нит може приступити критичном одељку означеном синхронизованом кључном речи.
Истовремене делове (делове који се извршавају истовремено) за апликацију можемо да напишемо помоћу синхронизоване кључне речи. Такође се решавамо услова трке тако што направимо блок кода или синхронизовану методу.
Када означимо да су блок или метода синхронизовани, делимо ресурсе унутар ових ентитета од истовременог приступа и тиме оштећења.
Врсте синхронизације
Постоје 2 типа синхронизације као што је објашњено у наставку:
# 1) Синхронизација процеса
Синхронизација процеса укључује истовремено извршавање више процеса или нити. На крају достижу стање у којем се ови процеси или нити обавезују на одређени редослед акција.
# 2) Синхронизација нити
У синхронизацији нити, више нити покушава да приступи дељеном простору. Нити се синхронизују на такав начин да заједничком простору истовремено приступа само једна нит.
Синхронизација процеса је изван делокруга овог упутства. Стога ћемо овде разговарати само о синхронизацији нити.
У Јави синхронизовану кључну реч можемо користити са:
- Блок кода
- Метод
Горе наведени типови су међусобно искључиви типови синхронизације нити. Међусобно изузеће спречава нити да приступају дељеним подацима да ометају једна другу.
Други тип синхронизације нити је „ИнтерТхреад комуникација“ која се заснива на сарадњи између нити. Интертхреад комуникација је изван делокруга овог водича.
Пре него што наставимо са синхронизацијом блокова и метода, применимо Јава програм да демонстрирамо понашање нити када синхронизација не постоји.
Вишеструки навој без синхронизације
Следећи Јава програм има више нити које нису синхронизоване.
class PrintCount { //method to print the thread counter public void printcounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run method for thread public void run() { PD.printcounter(); System.out.println('Thread ' + threadName + ' exiting.'); } //start method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create two instances of thread class ThreadCounter T1 = new ThreadCounter( 'ThreadCounter_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'ThreadCounter_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Оутпут
Из излаза можемо видети да је изузетак недоследан, пошто се нити не синхронизују. Обе нити почињу, а затим приказују бројач једну за другом. Обе нити излазе на крају.
Из датог програма, прва нит је требала изаћи након приказивања вриједности бројача, а затим је друга нит требала почети приказивати вриједности бројача.
Идемо сада на синхронизацију и започнимо са синхронизацијом блок-кода.
Блок синхронизованог кода
Синхронизовани блок се користи за синхронизацију блока кода. Овај блок се обично састоји од неколико редова. Синхронизовани блок се користи када не желимо да се синхронизује цела метода.
На пример, имамо метод са рецимо 75 линија кода. Од тога само 10 редова кода треба да се извршавају по једној нити истовремено. У овом случају, ако целокупну методу учинимо синхронизованом, то ће представљати оптерећење за систем. У таквим ситуацијама користимо синхронизоване блокове.
Опсег синхронизоване методе је увек мањи од опсега синхронизоване методе. Синхронизована метода закључава објекат дељеног ресурса који треба да користи више нити.
Општа синтакса синхронизованог блока је приказана доле:
synchronized (lock_object){ //synchronized code statements }
Овде је „лоцк_објецт“ израз референце на објекту на којем треба добити закључавање. Дакле, кад год нит жели да приступи синхронизованим изразима унутар блока ради извршавања, тада мора да добије закључавање на монитору „лоцк_објецт“.
Као што је већ речено, синхронизована кључна реч осигурава да само једна нит може истовремено да добије браву, а све остале нити морају да сачекају да се нит која држи браву заврши и отпусти браву.
Белешка
- Баци се „НуллПоинтерЕкцептион“ ако је лоцк_објецт који је коришћен Нулл.
- Ако конац спава док још увек држи браву, брава се не ослобађа. Остале нити током овог времена спавања неће моћи да приступе дељеном објекту.
Сада ћемо представити горњи пример који је већ примењен са малим променама. У ранијем програму нисмо синхронизовали код. Сада ћемо користити синхронизовани блок и упоредити излаз.
Вишеструки навој са синхронизацијом
У доњем програму Јава користимо синхронизовани блок. У методи извођења синхронизујемо код линија које исписују бројач за сваку нит.
class PrintCount { //print thread counter public void printCounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run () method for thread with synchronized block public void run() { synchronized(PD) { PD.printCounter(); } System.out.println('Thread ' + threadName + ' exiting.'); } //start () method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create thread instances ThreadCounter T1 = new ThreadCounter( 'Thread_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'Thread_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Оутпут
Сада је излаз овог програма који користи синхронизовани блок прилично доследан. Као што се и очекивало, обе нити почињу да се извршавају. Прва нит је завршила са приказивањем вредности бројача и излаза. Тада друга нит приказује вредности бројача и излази.
Синхронизовани метод
Размотримо синхронизовани метод у овом одељку. Раније смо видели да мали блок који се састоји од мање кодних линија можемо прогласити синхронизованим блоком. Ако желимо да се целокупна функција синхронизује, онда метод можемо прогласити синхронизованим.
Када се метода синхронизује, тада ће само једна нит моћи истовремено да упути позив методи.
Општа синтакса за писање синхронизоване методе је:
synchronized method_name (parameters){ //synchronized code }
Баш као и синхронизовани блок, у случају синхронизоване методе, потребан нам је лоцк_објецт који ће користити нити које приступају синхронизованој методи.
За синхронизовани метод, објекат закључавања може бити једно од следећег:
- Ако је синхронизовани метод статичан, онда је објект закључавања дат објектом .цласс.
- За не-статичку методу, објект закључавања даје тренутни објекат, тј. „Овај“ објекат.
Посебна карактеристика синхронизоване кључне речи је то што она поново улази. То значи да синхронизовани метод може да позове други синхронизовани метод са истом бравом. Дакле, нит која држи браву може приступити другој синхронизованој методи без потребе да набави другу браву.
Синхронизовани метод је приказан на следећем примеру.
class NumberClass { //synchronized method to print squares of numbers synchronized void printSquares(int n) throws InterruptedException { //iterate from 1 to given number and print the squares at each iteration for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + ' :: '+ i*i); Thread.sleep(500); } } } public class Main { public static void main(String args()) { final NumberClass number = new NumberClass(); //create thread Runnable thread = new Runnable() { public void run() { try { number.printSquares(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; //start thread instance new Thread(thread, 'Thread One').start(); new Thread(thread, 'Thread Two').start(); } }
Оутпут
У горе наведеном програму користили смо синхронизовану методу за штампање квадрата броја. Горња граница броја се методи преноси као аргумент. Затим се почевши од 1, квадрат сваког броја штампа док се не достигне горња граница.
У главној функцији креира се инстанца нити. Свакој инстанци нити прослеђује се број за испис квадрата.
Као што је горе поменуто, када је метода коју треба синхронизовати статична, онда је објект класе укључен у класу, а не објекат. То значи да ћемо се закључати на класу, а не на објекат. То се назива статичка синхронизација.
најбоље аниме странице за гледање анимеа бесплатно
Следећи пример је дат у наставку.
class Table{ //synchronized static method to print squares of numbers synchronized static void printTable(int n){ for(int i=1;i<=10;i++){ System.out.print(n*i + ' '); try{ Thread.sleep(400); }catch(Exception e){} } System.out.println(); } } //thread class Thread_One class Thread_One extends Thread{ public void run(){ Table.printTable(2); } } //thread class Thread_Two class Thread_Two extends Thread{ public void run(){ Table.printTable(5); } } public class Main{ public static void main(String t()){ //create instances of Thread_One and Thread_Two Thread_One t1=new Thread_One (); Thread_Two t2=new Thread_Two (); //start each thread instance t1.start(); t2.start(); } }
Оутпут
У горњем програму исписујемо таблице множења бројева. Сваки број чија табела се штампа је инстанца нити различите класе нити. Тако штампамо таблице множења од 2 и 5, тако да имамо две класе „тхреад_оне“ и „тхреад_тво“ за штампање табела 2, односно 5.
Да резимирамо, синхронизована кључна реч Јава врши следеће функције:
- Синхронизована кључна реч у Јави гарантује међусобно искључив приступ дељеним ресурсима пружајући механизам закључавања. Закључавање такође спречава услове трке.
- Користећи синхронизовану кључну реч, спречавамо истовремене грешке у програмирању у коду.
- Када је метода или блок декларисан као синхронизован, тада је нити потребна ексклузивна брава да би ушла у синхронизовану методу или блок. Након извршавања потребних радњи, нит отпушта браву и испразниће операцију писања. На овај начин ће елиминисати грешке у меморији повезане са недоследношћу.
Испарљиво у Јави
Хлапљива кључна реч у Јави користи се да класе чине нитима сигурним. Такође користимо променљиву кључну реч за модификовање вредности променљиве различитим нитима. Хлапљива кључна реч може се користити за декларисање променљиве са примитивним типовима као и објектима.
У одређеним случајевима променљива кључна реч се користи као алтернатива синхронизованој кључној речи, али имајте на уму да она није замена за синхронизовану кључну реч.
Када се променљива прогласи нестабилном, њена вредност се никада не кешира, већ се увек чита из главне меморије. Хлапљива променљива гарантује редослед и видљивост. Иако се променљива може прогласити променљивом, класе или методе не можемо прогласити променљивим.
Размотрите следећи блок кода:
class ABC{ static volatile int myvar =10; }
У горњем коду променљива мивар је статична и променљива. Статичка променљива се дели између свих објеката класе. Хлапљива променљива се увек налази у главној меморији и никада се не меморише.
Отуда ће у главној меморији бити само једна копија мивара и све радње читања / писања ће се извршити на овој променљивој из главне меморије. Да мивар није проглашен испарљивим, тада би сваки објект нити имао различиту копију која би резултирала недоследностима.
Неке од разлика између променљивих и синхронизованих кључних речи наведене су у наставку.
Хлапљива кључна реч | Синхронизована кључна реч |
---|---|
Хлапљива кључна реч користи се само са променљивим. | Синхронизована кључна реч користи се са блоковима и методама кода. |
Хлапљива кључна реч не може блокирати нит за чекање. | Синхронизована кључна реч може блокирати нит за чекање. |
Перформансе нити побољшавају се помоћу Волатиле. | Перформансе навоја се донекле погоршавају са синхронизованим. |
Испарљиве променљиве налазе се у главној меморији. | Синхронизоване конструкције се не налазе у главној меморији. |
Хлапљиво синхронизује по једну променљиву између меморије нити и главне меморије. | Синхронизована кључна реч синхронизује све променљиве одједном. |
Застој у Јави
Видели смо да можемо синхронизовати више нити помоћу синхронизоване кључне речи и учинити програме сигурним за нит. Синхронизацијом нити осигуравамо да се више нити извршавају истовремено у окружењу са више нити.
Међутим, понекад се догоди ситуација у којој нити више не могу истовремено да функционишу. Уместо тога, чекају бескрајно. То се дешава када једна нит чека на ресурс и тај ресурс блокира друга нит.
С друге стране, друга нит чека на ресурсу који је блокиран првом нити. Таква ситуација доводи до „ћорсокака“ на Јави.
Застој у Јави приказан је помоћу доње слике.
Као што видимо из горњег дијаграма, нит А је закључала ресурс р1 и чека ресурс р2. Нит Б, с друге стране, блокирао је ресурс р2 и чека на р1.
Дакле, ниједна нит не може завршити своје извршавање уколико се не домогну ресурса на чекању. Ова ситуација је резултирала застојем у којем обе нити бескрајно чекају ресурсе.
Доље је дат пример мртвих блокада у Јави.
public class Main { public static void main(String() args) { //define shared resources final String shared_res1 = 'Java tutorials'; final String shared_res2 = 'Multithreading'; // thread_one => locks shared_res1 then shared_res2 Thread thread_one = new Thread() { public void run() { synchronized (shared_res1) { System.out.println('Thread one: locked shared resource 1'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res2) { System.out.println('Thread one: locked shared resource 2'); } } } }; // thread_two=> locks shared_res2 then shared_res1 Thread thread_two = new Thread() { public void run() { synchronized (shared_res2) { System.out.println('Thread two: locked shared resource 2'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res1) { System.out.println('Thread two: locked shared resource 1'); } } } }; //start both the threads thread_one.start(); thread_two.start(); } }
Оутпут
У горњем програму имамо два заједничка ресурса и две нити. Обе нити покушавају да приступе дељеним ресурсима један по један. Излаз приказује обе нити како закључавају по један ресурс док чекају остале. На тај начин се ствара застој.
Иако не можемо зауставити да се ситуације у ћорсокаку у потпуности догоде, сигурно их можемо избећи предузимањем неких корака.
У наставку су наведена средства помоћу којих можемо избећи мртве тачке у Јави.
# 1) Избегавањем угнежђених брава
Поседовање угнежђених брава је најважнији разлог застоја. Угњеждене браве су браве које се дају више нити. Стога треба избегавати давање брава на више нити.
# 2) Користите нит Придружи се
Требали бисмо користити Тхреад.јоин са максималним временом како би нити могле да искористе максимално време за извршавање. Ово ће спречити застој који се углавном јавља док једна нит непрекидно чека друге.
# 3) Избегавајте непотребно закључавање
Требали бисмо закључати само потребан код. Имати непотребне браве за код може довести до застоја у програму. Како застоји могу разбити код и ометати ток програма, требали бисмо бити склони избјегавању застоја у нашим програмима.
Често постављана питања
П # 1) Шта је синхронизација и зашто је важна?
Одговор: Синхронизација је процес управљања приступом заједничком ресурсу више нити. Без синхронизације, више нити може истовремено ажурирати или променити дељени ресурс, што резултира недоследностима.
Стога бисмо требали осигурати да се у окружењу са више нити навоји синхронизују тако да се начин на који приступају дељеним ресурсима међусобно искључују и доследно.
П # 2) Шта је синхронизација и несинхронизација у Јави?
Одговор: Синхронизација значи да је конструкција заштићена од нити. То значи да више нити не може истовремено приступити конструкцији (блок кода, метода итд.).
Несинхронизоване конструкције нису заштићене од нити. Више нити може у било ком тренутку да приступи несинхронизованим методама или блоковима. Популарна не синхронизована класа у Јави је СтрингБуилдер.
П # 3) Зашто је потребна синхронизација?
Одговор: Када процеси треба да се извршавају истовремено, потребна нам је синхронизација. То је зато што су нам потребни ресурси који се могу делити међу многим процесима.
Да бисмо избегли сукобе између процеса или нити за приступ дељеним ресурсима, морамо да их синхронизујемо тако да све нити добију приступ ресурсима, а апликација такође несметано ради.
П # 4) Како се добија синхронизовани АрраиЛист?
Одговор: Можемо користити методу Цоллецтионс.синцхронизед лист са АрраиЛист као аргументом за претварање АрраиЛист у синхронизовану листу.
П # 5) Да ли је ХасхМап синхронизован?
вр слушалице које раде са кбок оне
Одговор: Не, ХасхМап није синхронизован, али је ХасхТабле синхронизован.
Закључак
У овом упутству детаљно смо разговарали о синхронизацији нити. Заједно са њим, такође смо сазнали о променљивој кључној речи и застојима у Јави. Синхронизација се састоји од синхронизације процеса и нити.
У окружењу са више нити више нас брине синхронизација нити. Овде смо видели приступ синхронизоване кључне речи синхронизације нити.
Застој је ситуација у којој више нити бескрајно чека ресурсе. Видели смо пример застоја у Јави заједно са методама за избегавање застоја у Јави.
=> Посетите овде да бисте научили Јаву из нуле.
Препоручено читање
- Тхреад.Слееп () - Метода спавања нити () у Јави са примерима
- Јава теме са методама и животним циклусом
- Основе Јава-а: Јава синтакса, Јава Цласс и основни Јава концепти
- Мултитхреадинг у Јави - Водич са примерима
- Мултитхреадинг у Ц ++ са примерима
- Водич за ЈАВА за почетнике: 100+ практичних Јава видео водича
- Јава компоненте: Јава платформа, ЈДК, ЈРЕ и Јава виртуелна машина
- Јава Стринг Водич | Јава стринг методе са примерима