CodeGym /Java блог /Случаен /Синхронизиране на нишки. Синхронизираният оператор
John Squirrels
Ниво
San Francisco

Синхронизиране на нишки. Синхронизираният оператор

Публикувано в групата
здрасти Днес ще продължим да разглеждаме функциите на многонишковото програмиране и ще говорим за синхронизиране на нишки. Синхронизиране на нишки.  Синхронизираният оператор - 1

Какво е синхронизация в Java?

Извън областта на програмирането, това предполага подреждане, което позволява на две устройства or програми да работят заедно. Например смартфон и компютър могат да се синхронизират с акаунт в Google, а акаунт в уебсайт може да се синхронизира с акаунти в социални мрежи, така че да можете да ги използвате за влизане. Синхронизирането на нишки има подобно meaning: това е подреждане, при което нишките взаимодействат с взаимно. В предишните уроци нишките ни живееха и работеха отделно една от друга. Един извършваше изчисления, втори спеше, а трети показваше нещо на конзолата, но не си взаимодействаха. В реалните програми такива ситуации са рядкост. Множество нишки могат активно да работят и да променят един и същ набор от данни. Това създава проблеми. Представете си множество нишки, които пишат текст на едно и също място, например в текстов файл or конзолата. В този случай файлът or конзолата стават споделен ресурс. Нишките не знаят за съществуването на другия, така че те просто пишат всичко, което могат във времето, определено им от планировчика на нишки. В скорошен урок видяхме пример накъде води това. Нека си го припомним сега: Синхронизиране на нишки.  Синхронизираният оператор - 2Причината се крие във факта, че нишките работят със споделен ресурс (конзолата), без да координират действията си помежду си. Ако планировчикът на нишки разпредели време за Thread-1, тогава той моментално записва всичко в конзолата. Какво други теми вече са успели да напишат or не, няма meaning. Резултатът, Howто виждате, е отчайващ. Ето защо те въведоха специална концепция, mutex (взаимно изключване) в многопоточното програмиране. Целта на mutexе да осигури механизъм, така че само една нишка да има достъп до обект в определен момент. Ако Thread-1 придобие mutex на обект A, другите нишки няма да имат достъп и да променят обекта. Другите нишки трябва да изчакат, докато мютексът на обект А бъде освободен. Ето пример от живота: представете си, че вие ​​и още 10 непознати участвате в упражнение. Редувайки се, трябва да изразите идеите си и да обсъдите нещо. Но тъй като се виждате за първи път, за да не се прекъсвате непрекъснато и да се ядосвате, използвате „говореща топка“: само човекът с топката може да говори. По този начин ще имате добра и ползотворна дискусия. По същество топката е мютекс. Ако mutex на обект е в ръцете на една нишка, други нишки не могат да работят с обекта.Objectклас, което означава, че всеки обект в Java има такъв.

Как работи синхронизираният оператор

Нека се запознаем с нова ключова дума: синхронизирано . Използва се за маркиране на определен блок от code. Ако codeов блок е маркиран с synchronizedключовата дума, тогава този блок може да бъде изпълнен само от една нишка наведнъж. Синхронизацията може да се реализира по различни начини. Например, чрез деклариране на цял метод за синхронизиране:

public synchronized void doSomething() {

   // ...Method logic
}
Или напишете codeов блок, където синхронизирането се извършва с помощта на няHowъв обект:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Значението е просто. Ако една нишка влезе в codeовия блок, маркиран с synchronizedключовата дума, тя незабавно улавя мутекса на обекта и всички други нишки, опитващи се да влязат в същия блок or метод, са принудени да изчакат, докато предишната нишка завърши работата си и освободи монитора. Синхронизиране на нишки.  Синхронизираният оператор - 3Между другото! По време на курса вече сте виждали примери за synchronized, но те изглеждаха различно:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Темата е нова за вас. И, разбира се, ще има объркване със синтаксиса. Така че, запомнете го веднага, за да избегнете по-късно объркване от различните начини на писане. Тези два начина на писане означават едно и също нещо:

public void swap() {

   synchronized (this)
   {
       // ...Method logic
   }
}


public synchronized void swap() {

   }
}
В първия случай вие създавате синхронизиран блок от code веднага след въвеждане на метода. Синхронизира се от thisобекта, т.е. текущия обект. И във втория пример прилагате synchronizedключовата дума към целия метод. Това прави ненужно изричното посочване на обекта, който се използва за синхронизация. Тъй като целият метод е маркиран с ключовата дума, методът автоматично ще се синхронизира за всички екземпляри на класа. Няма да се впускаме в дискусия за това кой начин е по-добър. Засега изберете Howъвто начин ви харесва най-добре :) Основното нещо е да запомните: можете да декларирате метод синхронизиран само когато цялата му логика се изпълнява от една нишка наведнъж. Например, би било грешка да направите следния doSomething()метод синхронизиран:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Както можете да видите, част от метода съдържа логика, която не изисква синхронизация. Този code може да се изпълнява от множество нишки едновременно и всички критични места са отделени в отделен synchronizedблок. И още нещо. Нека разгледаме внимателно нашия пример от урока със смяна на имена:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Забележка: синхронизирането се извършва с помощта наthis. Тоест с помощта на конкретенMyClassобект. Да предположим, че имаме 2 нишки (Thread-1иThread-2) и само единMyClass myClassобект. В този случай, акоThread-1извикаmyClass.swap()метода, мутексът на обекта ще бъде зает и при опит за извикване методътmyClass.swap()щеThread-2виси, докато чака мутексът да бъде освободен. Ако ще имаме 2 нишки и 2MyClassобекта (myClass1иmyClass2), нашите нишки могат лесно едновременно да изпълняват синхронизираните методи на различни обекти. Първата нишка изпълнява това:

myClass1.swap();
Вторият изпълнява това:

myClass2.swap();
В този случай synchronizedключовата дума в swap()метода няма да повлияе на работата на програмата, тъй като синхронизирането се извършва с помощта на конкретен обект. И в последния случай имаме 2 обекта. Така нишките не създават проблеми една на друга. В края на краищата два обекта имат 2 различни мутекса и придобиването на единия е независимо от придобиването на другия .

Особености на синхронизацията при статичните методи

Но Howво ще стане, ако трябва да синхронизирате статичен метод ?

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static synchronized void swap() {
       String s = name1;
       name1 = name2;
       name2 = s;
   }

}
Не е ясно Howва роля ще играе mutex тук. В крайна сметка вече установихме, че всеки обект има мютекс. Но проблемът е, че не се нуждаем от обекти, за да извикаме MyClass.swap()метода: методът е статичен! И така, Howво следва? :/ Тук всъщност няма проблем. Създателите на Java са се погрижor за всичко :) Ако метод, който съдържа критична паралелна логика, е статичен, тогава синхронизацията се извършва на ниво клас. За по-голяма яснота можем да пренапишем горния code, Howто следва:

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
По принцип бихте могли сами да се сетите за това: Тъй като няма обекти, механизмът за синхронизация трябва по няHowъв начин да бъде вграден в самия клас. И това е така: можем да използваме класове за синхронизиране.
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION