"Hello, Amigo! We have a panacea—a cure for all diseases. As we've already seen, uncontrolled thread switching is a problem."

"Why can't the threads themselves decide when to switch to the next thread? Do everything they need to do and then signal, «I'm done!»?"

"Allowing threads themselves to control switching would be an even bigger problem. Suppose you have some poorly written code, and the thread never surrenders the CPU. Back in the day, this is how it worked. And it was quite a nightmare."

"Okay. So what's the solution?"

"Blocking other threads. This is how it works."

It became clear that threads interfere with each other when they try to use shared objects and/or resources. Just as we saw in the example with console output: there's one console and all the threads output to it. It's messy.

So a special object was invented: the mutex. It's like a sign on a bathroom door that says «available/occupied». It has two states: the object is available or occupied. These states are also called «locked» and «unlocked».

When a thread needs an object shared with other threads, it checks the mutex associated with the object. If the mutex is unlocked, then the thread locks it (marks it as «occupied») and starts using the shared resource. After the thread has done its business, the mutex is unlocked (marked as «available»).

If the thread wants to use the object and the mutex is locked, then the thread sleep while it waits. When the mutex is finally unlocked by the occupying thread, our thread will immediately lock it and start running. The analogy with a bathroom door sign is perfect.

"So how do I work with a mutex? Do I need to create special objects?"

"It's a lot simpler than that. Java's creators built this mutex into the Object class. So you don't even have to create it. It's part of every object. Here's how it all works:"

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

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
The swap method swaps the values of the name1 and name2 variables.

What might happen if it is called from two threads at the same time?

Actual code execution Code of the first thread Code of the second thread
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;
The bottom line
The values of the variables were swapped twice, returning to their original places.

Pay attention to the keyword synchronized.

"Yeah, what does it mean?"

"When a thread enters a block of code marked as synchronized, the Java machine immediately locks the mutex of the object indicated in parentheses after the word synchronized. No other thread can enter this block until our thread leaves it. As soon as our thread leaves the block marked synchronized, the mutex is immediately and automatically unlocked and will be available to be acquired by another thread."

If the mutex is occupied, then our thread will stand still and wait for it to free up.

"So simple and so elegant. That's a beautiful solution."

"Yes. But what do you think will happen in this case?"

Code Description
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;
}
}
}
The swap and swap2 methods share the same mutex (the this object).

What happens if one thread calls the swap method and another thread calls the swap2 method?

"Since the mutex is the same, the second thread will have to wait until the first thread leaves the synchronized block. So there won't be any problems with simultaneous access."

"Well done, Amigo! That's the correct answer!"

Now I'd like to point out that synchronized can be used to mark not only blocks of code, but also methods. Here's what that means:

Code What really happens
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;
}
}