"Hej, Amigo! Vi har ett universalmedel - ett botemedel mot alla sjukdomar. Som vi redan har sett är okontrollerad trådbyte ett problem."

"Varför kan inte trådarna själva bestämma när de ska byta till nästa tråd? Gör allt de behöver göra och sedan signalera "Jag är klar!"?"

"Att tillåta trådar själva att styra växling skulle vara ett ännu större problem. Anta att du har någon dåligt skriven kod, och tråden överlämnar aldrig CPU:n. Förr i tiden var det så här det fungerade. Och det var en ganska mardröm."

"Okej. Så vad är lösningen?"

" Blockerar andra trådar.  Så här fungerar det."

Det blev tydligt att trådar stör varandra när de försöker använda delade objekt och/eller resurser . Precis som vi såg i exemplet med konsolutgång: det finns en konsol och alla trådar som matas ut till den. Det är rörigt.

Så ett speciellt föremål uppfanns: mutexen . Det är som en skylt på en badrumsdörr som säger «tillgänglig / upptagen» . Den har två tillstånd: objektet är tillgängligt eller upptaget . Dessa tillstånd kallas också "låsta" och "olåsta".

När en tråd behöver ett objekt som delas med andra trådar, kontrollerar den mutex som är associerat med objektet. Om mutexen är upplåst låser tråden den (markerar den som "ockuperad") och börjar använda den delade resursen. Efter att tråden har gjort sina affärer låses mutexen upp (markerad som «tillgänglig»).

Om tråden vill använda objektet och mutexen är låst, så sover tråden medan den väntar. När mutexen äntligen låses upp av den upptagande tråden kommer vår tråd omedelbart att låsa den och börja köra. Analogin med ett badrumsdörrskylt är perfekt.

"Så hur arbetar jag med en mutex? Behöver jag skapa speciella objekt?"

"Det är mycket enklare än så. Javas skapare byggde in den här mutexen i klassen Object. Så du behöver inte ens skapa den. Den är en del av varje objekt. Så här fungerar det hela:"

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

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
Bytningsmetoden byter ut värdena för variablerna name1 och name2.

Vad kan hända om det anropas från två trådar samtidigt?

Faktisk kodexekvering Koden för den första tråden Koden för den andra tråden
String s1 = name1; //Ally
name1 = name2; //Lena
name2 = s1; //Ally

String s2 = name1; //Lena
name1 = name2; //Ally
name2 = s2; //Lena
String s1 = name1;
name1 = name2;
//other thread is running
name2 = s1;
//the thread waits until the mutex is unlocked

String s2 = name1;
name1 = name2;
//other thread is running
//other thread is running
name2 = s2;
Poängen
Variablernas värden byttes två gånger och återgick till sina ursprungliga platser.

Var uppmärksam på nyckelordet  synkroniserat .

"Ja, vad betyder det?"

"När en tråd går in i ett kodblock markerat som synkroniserat, låser Java-maskinen omedelbart mutexet för objektet som anges inom parentes efter ordet synchronized. Ingen annan tråd kan gå in i detta block förrän vår tråd lämnar det. Så snart vår tråd lämnar det. blocket markerat synkroniserat, mutexet låses upp omedelbart och automatiskt och kommer att vara tillgängligt för att hämtas av en annan tråd."

Om mutexen är upptagen kommer vår tråd att stå stilla och vänta på att den ska frigöras.

"Så enkelt och så elegant. Det är en vacker lösning."

"Ja. Men vad tror du kommer att hända i det här fallet?"

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

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

public void swap2()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
Metoderna swap och swap2 delar samma mutex (det här objektet).

Vad händer om en tråd anropar swapmetoden och en annan tråd anropar swap2-metoden?

"Eftersom mutexen är densamma måste den andra tråden vänta tills den första tråden lämnar det synkroniserade blocket. Så det kommer inte att vara några problem med samtidig åtkomst."

"Bra gjort, Amigo! Det är rätt svar!"

Nu vill jag påpeka att synkroniserad kan användas för att markera inte bara kodblock, utan även metoder. Så här betyder det:

Koda Vad händer egentligen
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

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

public static synchronized void swap2()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

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

public static void swap2()
{
synchronized (MyClass.class)
{
String s = name1;
name1 = name2;
name2 = s;
}
}