Update:
When I first posted this, I was fairly certain the code was broken. Now, I'm no longer sure about what I'd observed. The biggest problem I'm having is that I can't seem to apply 17.4. Memory Model and state straight out whether it should or shouldn't work.
This following code is broken.
It's overly complex for what it's trying to achieve, but furthermore, it's thread-unsafe in that I've observed that it can indefinitely wait at c. I'm not worried about the former (one could use a ReentrantLock or CountDownLatch for sounder code), but I'm wondering, what's the reason for the latter?
static final ConcurrentHashMap<Integer, Object> mutex = new ConcurrentHashMap<>();
public static brokenFoo() {
Object ourLock = new Object();
for (;;) {
Object theirLock = mutex.putIfAbsent(0, ourLock);
if (theirLock == null) {
break;
}
synchronized (theirLock) { // a
if (mutex.get(0) != theirLock) { // b
continue;
}
theirLock.wait(); // c
} // d
}
try {
// critical section
} finally {
synchronized (ourLock) { // e
mutex.remove(0); // f
ourLock.notifyAll(); // g
} // h
}
}
I've thought in terms of happens-befores:
hb(f, h) and hb(h, a) therefore hb(f, a)
hb(c, d) and hb(d, e) therefore hb(c, e)
But, this doesn't seem to prove or disprove anything.
Edit: (Above question fails to really explain what this code should do.)
Expected:
brokenFoo() is called by multiple threads and the above code is supposed to provide mutual exclusion over // critical section.
If two or more threads enter brokenFoo() at the same time, only one should proceed to // critical section, while others wait somewhere prior.
After the thread in // critical section has exited, another should proceed to take its place.
Actual:
It's been observed that there're threads that are waiting at c even though no other threads are in brokenFoo().
It might be the case that one thread calls notifyAll() before another thread starts to wait(). This may happen due to a spurious wakeup:
thread 1 enters the critical section
thread 2 starts to wait()
a spurious wakeup occurs in thread 2
thread 1 enters the synchronized block and notifies on the lock
thread 2 enters the synchronized block and waits indefinitely
Or thread 1 just happened to execute before thread 2. While your code is correct in terms of the JMM, its liveness is not guaranteed. That's why you should use a CountDownLatch instead of the notify/wait mechanism.
Related
So I'm attending a course in multi threaded development and are currently learning about semaphores. In our latest assignment we are supposed to use three threads and two queues. The writer thread will write chars to the first queue, then a "encryptor" thread will read the chars from that queue, encrypt the char and then add it to the second queue. Then we have a reader thread which reads from the second queue. To handle synchronization we are supposed to use semaphore's and mutex, but I managed without any:
public class Buffer {
private Queue<Character> qPlain = new LinkedList<Character>();
private Queue<Character> qEncrypt = new LinkedList<Character>();
private final int CAPACITY = 3;
public Buffer() {
System.out.println("New Buffer!");
}
public synchronized void addPlain(char c) {
while (qPlain.size() == CAPACITY) {
try {
wait();
System.out.println("addPlain is waiting to add Data");
} catch (InterruptedException e) {
}
}
qPlain.add(c);
notifyAll();
System.out.println("addPlain Adding Data-" + c);
}
public synchronized char removePlain() {
while (qPlain.size() == 0) {
try {
wait();
System.out.println("----------removePlain is waiting to return Data.");
} catch (InterruptedException e) {
}
}
notifyAll();
char c = qPlain.remove();
System.out.println("---------------removePlain Returning Data-" + c);
return c;
}
public synchronized void addEncrypt(char c) {
while (qEncrypt.size() == CAPACITY) {
try {
wait();
System.out.println("addEncrypt is waiting to add Data");
} catch (InterruptedException e) {
}
}
qEncrypt.add(c);
notifyAll();
System.out.println("addEncrypt Adding Data-" + c);
}
public synchronized char removeEncrypt() {
while (qEncrypt.size() == 0) {
try {
wait();
System.out.println("----------------removeEncrypt is waiting to return Data.");
} catch (InterruptedException e) {
}
}
notifyAll();
char c = qEncrypt.remove();
System.out.println("--------------removeEncrypt Returning Data-" + c);
return c;
}
}
So this works fine, but I'm not going to pass as I haven't used any semaphore. I do understand the concept, but I just don't see the point to use any in this case. I have 2 queues and just one reader and writer for each one.
EDIT: Updated with Semaphores instead. It almost works, problem arises when the removePlain() method get's called when the queue is empty. I'm pretty sure I should block it, but I'm lost here. Could I not just use a mutex here instead?
public class Buffer {
private Semaphore encryptedSem = new Semaphore(0);
private Semaphore decryptedSem = new Semaphore(0);
private final Queue<Character> qPlain = new LinkedList<Character>();
private final Queue<Character> qEncrypt = new LinkedList<Character>();
private final int CAPACITY = 3;
private boolean startedWrite = false;
private boolean startedRead = false;
/**
* Adds a character to the queue containing non encrypted chars.
*
* #param c
*/
public void addPlain(char c) {
// Makes sure that this writer executes first.
if (!startedWrite) {
startedWrite = true;
encryptedSem = new Semaphore(1);
}
if (qPlain.size() < CAPACITY) {
aquireLock(encryptedSem);
System.out.println("addPlain has lock");
qPlain.add(c);
realeseLock(encryptedSem);
}
}
/**
* Removes and returns the next char in the non encrypted queue.
*
* #return
*/
public char removePlain() {
// TODO Need to fix what happens when the queue is 0. Right now it just
// returns a char that is 0. This needs to be blocked somehow.
char c = 0;
if (qPlain.size() > 0) {
aquireLock(encryptedSem);
System.out.println("removePlain has lock");
c = qPlain.remove();
realeseLock(encryptedSem);
} else {
System.out.println("REMOVEPLAIN CALLED WHEN qPlain IS EMPTY");
}
return c;
}
/**
* Adds a character to the queue containing the encrypted chars.
*
* #param c
*/
public void addEncrypt(char c) {
if (!startedRead) {
startedRead = true;
decryptedSem = new Semaphore(1);
}
if (qEncrypt.size() < CAPACITY) {
aquireLock(decryptedSem);
System.out.println("addEncrypt has lock");
qEncrypt.add(c);
realeseLock(decryptedSem);
}
}
/**
* Removes and returns the next char in the encrypted queue.
*
* #return
*/
public char removeEncrypt() {
char c = 0;
if (qEncrypt.size() > 0) {
aquireLock(decryptedSem);
System.out.println("removeEncrypt has lock");
c = qEncrypt.remove();
realeseLock(decryptedSem);
}
return c;
}
/**
* Aquries lock on the given semaphore.
*
* #param sem
*/
private void aquireLock(Semaphore sem) {
try {
sem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Realeses lock on the given semaphore.
*
* #param sem
*/
private void realeseLock(Semaphore sem) {
sem.release();
}
}
OK, so trying to adress your concerns, without doing your homework :-)
About your first sample
At first sight, this is a working sample. You are using a form of mutual exclusion through the synchronized keyword, which allows you to use this.wait/notify correctly. This also provides safeguards seeing every thread synchronizes on the same monitor, which provides adequate happen-before safety.
In other words, thanks to this single monitor, you are assured that anything under the synchronized methods is executed exclusively and that these methods side-effects are visible inside the other methods.
Only minor gripe is that your queues are not final, which according to safe object publication guidelines and depending on how your whole system/threads is bootstraped, might lead to visibility issues. Rule of thumb in multithreaded code (and maybe even generally) : whatever can be made final should be.
The real problem with your code is that it does not fulfill your requirements : use semaphores.
About your second sample
Unsafe boolean mutation
This one has real issues. First, your startedWrite/ startedRead booleans : you mutate them (change their true/false value) outside of any synchronization (lock, semaphores, syncrhonized, ... nothing at all). This is unsafe, under the java memory model it would be legal for a thread that has not performed the mutation to not see the mutated value. Put it another way, the first write could set startedWrite to true, and it could be that all other threads never see that true value.
Some discussions on this :
- https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html
- Java's happens-before and synchronization
So anything that relies on these booleans is inherently flawed in your sample. That is, your Semaphore assignments, for one thing.
Several ways to correct this :
Always mutate shared state under a synchonization tool of some sort (in your first sample, it was the synchronized keyword, and here it could be your semaphores), and make sure that the same tool is used by all threads mutating or accessing the variable
Or use a concurrently safe type, like AtomicBoolean is this case, which has concurrency guarantees that any mutation is made visible to other threads
Race conditions
Another issue with your second code sample, is that you check the sizes of your queues before taking a lock and modifiying them, that is :
if (qPlain.size() > 0) {
aquireLock(encryptedSem);
...
c = qPlain.remove();
realeseLock(encryptedSem);
} else {
System.out.println("REMOVEPLAIN CALLED WHEN qPlain IS EMPTY");
}
Two concurrent threads could perform the check at the first line at the same time, and behave wrongly. Typical scenario is :
qplain has a size of 1
Thread 1 arrives at the if, checks that qplain is not empty, the check succeeds, then thread 1 is paused by the OS scheduler right here and now
Thread 2 arrives at the same if and the same check succeeds for the same reason
Thread 1 and Thread 2 resume from there on, both think they are allowed to take 1 element out of qplain which is wrong, because qplain has a size of 1 actually.
It will fail. You should have had a mutual exclusion of some sort. You can not (rule of thumb again) perform a check and after it perform a mutation under a lock. Both the check and the mutation should happen in, broadly speaking, the same lock. (Or you are a very advanced multithreading kind of guy and you know optimistic locking and stuf like that really well).
Possible deadlock
Another rule of thumb: any time you acquire and release a lock and/or a resource at the same call site, you should have a try/finally pattern.
That is, no matter how it is done, your code should always look like
acuquireSemaphore();
try {
// do something
} finally {
releaseSemaphore();
}
Same goes for locks, input or output streams, sockets, ... Failure to do so may lead to your semaphore being acquired but never released, especially in case of an uncaught exception. So do use try and finally around your resources.
Conclusions
With such serious flaws, I did not really read your code to see if the "spirit" of it works. Maybe it does, but at this point, it's not worth it to check it out further.
Going forward with your assignment
You are asked to use two tools : Semaphores and mutual exclusion (e.g. synchonized, or Lock I guess). Both are not exactly the same thing!
You probablye get mutual exclusions, as your first sample showed. Probably not Semaphores yet. The point of semaphores, is that they (safely) manage a number of "permits". One (a thread) can ask for a permit, and if the semaphore has one available and grants it, one can proceed with one's work. Otherwise, one is put in a "holding pattern" (a wait) untill a permit is available. At some point, one* is expected to give the permit back to the Semaphore, for others to use.
(*Please note : it is not mandatory for a semaphore to work that threads performing permit acquisition are the one to perform permit release. It is part of what make a lock and a semaphore so different, and it's a good thing).
Let's start simple : a Semaphore that only has one permit can be used as a mutual exclusion. Bonus point : it can be released by another thread than the one that acquired it. That makes it ideal for message passing between threads : they can exchange permits.
What does it remember us of ? Of wait / notify of course!
A possible path to a solution
So we have a semaphore, and it has a number of permits. What could the meaning of this number be ? A natural candidate is : have a Semaphore hold the number of elements inside the queues. At first, this could be zero.
Each time somebody puts an element in the queue, it raises the number of permits by one.
Each time somebody takes an element off the queue, it lowers the number of permits.
Then : trying to take an element off an empty queue means trying to acquire a permit from an empty semaphore, it will automatically block the caller. This seems to be what you want.
But!
We're yet to have a definition for "putting an element on top of a full queue". That is because semaphores are not bounded in permits. One can start with an empty semaphore and call "release" a thousand times, and end up with a 1000 permits available. We wil blow our maximal capacity without any kind of bounds.
Let's say we have a workaround for that, we're still not done : we did not make sure at this point that readers and writers do not modify the queue at the same time. And this is crucial for correctneess !
So we need other ideas.
Well issue #2 is easy : we are allowed to use exclusive locks for this exercie, so we'll use them. Just make sure that any manipulation to the list itself is under a synchonized block using the same monitor.
Issue number one... Well, we have a Semaphore representing a "not empty" condition. That's one of the two pairs of wait/notify you had in your first sample. OK cool, let's make another Semaphore representing a "not full" condition, the other wait/notifyPair of your code sample !
So recap : use a semaphore for each couple of wait/notify in your original sample. Keep a mutual exclusion to actually modify the contents of the queue object. And be very carreful of the articulation of the mutual exclusion part with the semaphores, it is the crux of the matter.
And I'll stop there to let you walk down this path if you want.
Bonus point
You should not have to code the same thing twice here. In your samples, you coded twice the same logic (one for the "clear text", once for the "encrypted"), basically, wait for (at least) a spot before stacking a char, and wait for the presence of (at least) a char before popping a it.
This should be one and the same code / methods. Do it once, and you'll get it right (or wrong of course) at all times. Write it twice, you double the chance of mistakes.
Future thoughts
This is all still very complex, for something that could be done using a `BlockingQueuè but then again, homeworks do have another purpose :-).
A bit more complex, but this message passing pattern of signaling having a thread waiting for a "notEmpty" signal, while the other waits on a "notFull" signal is the exact use case of the JDK Condition object, which mimicks the use of wait/notify.
Suppose that I have an arraylist called myList of threads all of which are created with an instance of the class myRunnable implementing the Runnable interface, that is, all the threads share the same code to execute in the run() method of myRunnable. Now suppose that I have another single thread called singleThread that is created with an instance of the class otherRunnable implementing the Runnable interface.
The synchornization challenge I have to resolve for these threads is the following: I need all of the threads in myList to execute their code until certain point. Once reached this point, they shoud sleep. Once all and only all of the threads in myList are sleeping, then singleThread should be awakened (singleThread was already asleep). Then singleThread execute its own stuff, and when it is done, it should sleep and all the threads in myList should be awakened. Imagine that the codes are wrapped in while(true)'s, so this process must happen again and again.
Here is an example of the situation I've just described including an attempt of solving the synchronization problem:
class myRunnable extends Runnable
{
public static final Object lock = new Object();
static int count = 0;
#override
run()
{
while(true)
{
//do stuff
barrier();
//do stuff
}
}
void barrier()
{
try {
synchronized(lock) {
count++;
if (count == Program.myList.size()) {
count = 0;
synchronized(otherRunnable.lock) {
otherRunnable.lock.notify();
}
}
lock.wait();
}
} catch (InterruptedException ex) {}
}
}
class otherRunnable extend Runnable
{
public static final Object lock = new Object();
#override
run()
{
while(true)
{
try {
synchronized(lock) {
lock.wait();
} catch (InterruptedException ex) {}
// do stuff
try {
synchronized(myRunnable.lock) {
myRunnable.notifyAll();
}
}
}
}
class Program
{
public static ArrayList<Thread> myList;
public static void main (string[] args)
{
myList = new ArrayList<Thread>();
for(int i = 0; i < 10; i++)
{
myList.add(new Thread(new myRunnable()));
myList.get(i).start();
}
new Thread(new OtherRunnable()).start();
}
}
Basically my idea is to use a counter to make sure that threads in myList just wait except the last thread incrementing the counter, which resets the counter to 0, wakes up singleThread by notifying to its lock, and then this last thread goes to sleep as well by waiting to myRunnable.lock. In a more abstract level, my approach is to use some sort of barrier for threads in myList to stop their execution in a critical point, then the last thread hitting the barrier wakes up singleThread and goes to sleep as well, then singleThread makes its stuff and when finished, it wakes up all the threads in the barrier so they can continue again.
My problem is that there is a flaw in my logic (probably there are more). When the last thread hitting the barrier notifies otherRunnable.lock, there is a chance that an immediate context switch could occur, giving the cpu to singleThread, before the last thread could execute its wait on myRunnable.lock (and going to sleep). Then singleThread would execute all its stuff, would execute notifyAll on myRunnable.lock, and all the threads in myList would be awakened except the last thread hitting the barrier because it has not yet executed its wait command. Then, all those threads would do their stuff again and would hit the barrier again, but the count would never be equal to myList.size() because the last thread mentioned earlier would be eventually scheduled again and would execute wait. singleThread in turn would also execute wait in its first line, and as a result we have a deadlock, with everybody sleeping.
So my question is: what would be a good way to synchronize these threads in order to achieve the desired behaviour described before but at the same time in a way safe of deadlocks??
Based on your comment, sounds like a CyclicBarrier would fit your need exactly. From the docs (emphasis mine):
A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.
Unfortunately, I haven't used them myself, so I can't give you specific pointers on them. I think the basic idea is you construct your barrier using the two-argument constructor with the barrierAction. Have your n threads await() on this barrier after this task is done, after which barrierAction is executed, after which the n threads will continue.
From the javadoc for CyclicBarrier#await():
If the current thread is the last thread to arrive, and a non-null barrier action was supplied in the constructor, then the current thread runs the action before allowing the other threads to continue. If an exception occurs during the barrier action then that exception will be propagated in the current thread and the barrier is placed in the broken state.
We have two threads, Thread2 waits for Thread1 (receiving the messages from it)
class Thread1 .. {
run() {
synchronized(this) { some-work; notify(); }
}
}
class Thread2 .. {
run() {
while(true) {
synchronized(thread1) {
...
thread1.wait();
...
println("Got here"); // has received the notify() from Thread1
}
}
}
}
thread2.start() // thred2 is first to be ready to receive all messages from thread1
thread1.start()
After starting these threads in that sequence, we have the situation when thread2 is waiting for the notify() from thread1, and this will happen in couple of moments - the message "Got here" will be appeared.
But if I put a delay here:
class Thread2
run() {
while(true) {
sleep(1000); // the dalay
synchronized(thread1) { ..
}
Then the message 'Got Here' will be never appeared - because thread2 will miss the notify() from thread1 before the sycnronized(thread1) is reached - then we have a situation when Nothing To Wait.
The question is:
1.
Are these two lines atomic. Or better say is this gap between these two lines atomic?:
while(true) {
// gap
synchronized(thread1) {..thread.wait() ..}
}
2.
Or does it mean that we should not put any expression between while() and synchronized block? For example, we could have:
while(true) {
int a = 0; a++;
synchronized(thread1) {..thread.wait() ..}
Because it we have those expressions there then we have a risk of 'nothing-to-wait' situation?
wait and notify are not sufficient to create a signalling mechanism, for the reason that you've discovered: if you don't have any waiters, then the notify goes into the bit bucket.
A Semaphore is sufficient: if the sender returns the permit while the receiver is doing something else, then the receiver will immediately get that permit.
But, as some commenters said, a BlockingQueue is a better solution, as it means your code doesn't have to know anything about threading.
No gap between lines is "atomic", the concept of atomicity does not apply here.
If you want to avoid missing the notify, start thread1 in the body of thread2's run method.
Actually, you ask whether this could happen without the sleep(), right? Imho the answer is yes. While the "gap" is just that - nothing - the loop itself consists of actual instructions as well. In between them, the threads can get switched. IMHO it is also not garantueed that you reach Thread2.run before Thread1.run just because you started Thread2 first. I'm not sure how to solve this problem, though. Maybe have Thread1 wait for Thread2 somehow?
Why is it that two synchronized blocks can't be executed simultaneously by two different threads in Java.
EDIT
public class JavaApplication4 {
public static void main(String[] args) {
new JavaApplication4();
}
public JavaApplication4() {
Thread t1 = new Thread() {
#Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-1")) {
test(Thread.currentThread().getName());
} else {
test1(Thread.currentThread().getName());
}
}
};
Thread t2 = new Thread(t1);
t2.start();
t1.start();
}
public synchronized void test(String msg) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
System.out.println(msg);
}
}
public synchronized void test1(String msg) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
System.out.println(msg + " from test1");
}
}
}
Your statement is false. Any number of synchronized blocks can execute in parallel as long as they don't contend for the same lock.
But if your question is about blocks contending for the same lock, then it is wrong to ask "why is it so" because that is the purpose of the whole concept. Programmers need a mutual exclusion mechanism and they get it from Java through synchronized.
Finally, you may be asking "Why would we ever need to mutually exclude code segments from executing in parallel". The answer to that would be that there are many data structures that only make sense when they are organized in a certain way and when a thread updates the structure, it necessarily does it part by part, so the structure is in a "broken" state while it's doing the update. If another thread were to come along at that point and try to read the structure, or even worse, update it on its own, the whole thing would fall apart.
EDIT
I saw your example and your comments and now it's obvious what is troubling you: the semantics of the synchronized modifier of a method. That means that the method will contend for a lock on this's monitor. All synchronized methods of the same object will contend for the same lock.
That is the whole concept of synchronization, if you are taking a lock on an object (or a class), none of the other threads can access any synchronized blocks.
Example
Class A{
public void method1()
{
synchronized(this)//Block 1 taking lock on Object
{
//do something
}
}
public void method2()
{
synchronized(this)//Block 2 taking lock on Object
{
//do something
}
}
}
If one thread of an Object enters any of the synchronized blocks, all others threads of the same object will have to wait for that thread to come out of the synchronized block to enter any of the synchronized blocks. If there are N number of such blocks, only one thread of the Object can access only one block at a time. Please note my emphasis on Threads of same Object. The concept will not apply if we are dealing with threads from different objects.
Let me also add that if you are taking a lock on class, the above concept will get expanded to any object of the class. So if instead of saying synchronized(this), I would have used synchronized(A.class), code will instruct JVM, that irrespective of the Object that thread belongs to, make it wait for other thread to finish the synchronized block execution.
Edit: Please understand that when you are taking a lock (by using synchronized keyword), you are not just taking lock on one block. You are taking lock on the object. That means you are telling JVM "hey, this thread is doing some critical work which might change the state of the object (or class), so don't let any other thread do any other critical work" . Critical work, here refers to all the code in synchronized blocks which take lock on that particular Object (or class), and not only in one synchronized block.
This is not absolutely true. If you are dealing with locks on different objects then multiple threads can execute those blocks.
synchronized(obj1){
//your code here
}
synchronized(obj2){
//your code here
}
In above case one thread can execute first and second can execute second block , the point is here threads are working with different locks.
Your statement is correct if threads are dealing with same lock.Every object is associated with only one lock in java if one thread has acquired the lock and executing then other thread has to wait until first thread release that lock.Lock can be acquired by synchronized block or method.
Two Threads can execute synchronized blocks simultaneously till the point they are not locking the same object.
In case the blocks are synchronized on different object... they can execute simultaneously.
synchronized(object1){
...
}
synchronized(object2){
...
}
EDIT:
Please reason the output for http://pastebin.com/tcJT009i
In your example when you are invoking synchronized methods the lock is acquired over the same object. Try creating two objects and see.
I am trying to understand Java multi-threading constructs, and I am trying to write a simple implementation of blocking queue. Here is the code I have written:
class BlockingBoundedQueue<E>
{
#SuppressWarnings("unchecked")
BlockingBoundedQueue(int size)
{
fSize = size;
fArray = (E[]) new Object[size];
// fBlockingQueue = new ArrayBlockingQueue<E>(size);
}
BlockingQueue<E> fBlockingQueue;
public synchronized void put(E elem)
{
if(fCnt==fSize-1)
{
try
{
// Should I be waiting/locking on the shared array instead ? how ?
wait();
}
catch (InterruptedException e)
{
throw new RuntimeException("Waiting thread was interrupted during put with msg:",e);
}
}
else
{
fArray[fCnt++]=elem;
//How to notify threads waiting during take()
}
}
public synchronized E take()
{
if(fCnt==0)
{
try
{
// Should I be waiting/locking on the shared array instead ? how ?
wait();
}
catch (InterruptedException e)
{
throw new RuntimeException("Waiting thread was interrupted during take with msg:",e);
}
}
return fArray[fCnt--];
//How to notify threads waiting during put()
}
private int fCnt;
private int fSize;
private E[] fArray;
}
I want to notify threads waiting in Take() from put() and vice versa. Can someone please help me with the correct way of doing this.
I checked the java.utils implementation and it uses Condition and ReentrantLocks which are a little complex for me at this stage. I am okay of not being completely robust[but correct] for the sake of simplicity for now.
Thanks !
The short answer is, call notifyAll() where you have the comments //How to notify threads waiting during take()
Now for the more complete answer...
The reference to read is : Java Concurrency in Practice. The answer to your question is in there.
However, to briefly answer your question: in Java, threads synchronize by locking on the same object and using wait() and notify() to safely change state. The typical simplified flow is:
Thread A obtains a lock by entering a synchronized block on a lock object
Thread A checks some condition in a loop, if not "OK to go" call thread.wait(), which is a blocking call that "releases" the lock so other code synchronized on the same lock object can proceed
Thread B obtains the same lock and may do something that changes the condition thread A is waiting for. When it calls notifyAll(), thread A will wake up and recheck the condition and (may) proceed
Some things to remember about synchronization are:
it is about keeping state of objects consistent by making changes to state atomic. "Atomic" means the entire change (e.g. to multiple fields) is guaranteed to complete (no partial, and therefore inconsistent, changes)
it is cooperative - code synchronized on a given lock object has in common the state that is being changed and the conditions that allow that state change - you wait and notify about the same "subject". Each part of state should be guarded by its own lock object - usually a private field, e.g. private Object lock = new Object(); would be fine
methods that are synchronized use this as the lock object - doing this is easy but potentially expensive, because you are locking for every call, instead of just when you need to
static methods that are synchronized use the Class object as the lock object