I wrote this program to check if a thread_1 holding lock on two different objects: LOCK_OBJECT
and FULL
goes into waiting mode on LOCK_OBJECT
using FULL.wait()
. I didn't think the consumer would get the LOCK_OBJECT
lock, but the print didn't. So is there anything you missed?
Why does the consumer get the LOCK_OBJECT
lock based on the printed results?
This is my code:
public class TestSync {
private volatile Integer amount = 0;
private final Object LOCK_OBJECT = new Object();
private final Object FULL = new Object();
public void doubleSync() throws InterruptedException {
System.out.println("Producer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Producer get LOCK_OBJECT lock ");
Print.sleep(3000);
while (amount >= 0) {
synchronized (FULL) {
System.out.println("full!");
FULL.wait();
}
}
System.out.println("continue~");
amount++;
}
}
public void simpleSync() {
System.out.println("Consumer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Consumer get LOCK_OBJECT lock");
}
System.out.println("Consumer release LOCK_OBJECT lock");
}
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "one Thread-" + index);
return t;
}
});
threadPool.execute(() -> {
try {
new TestSync().doubleSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Print.sleep(1000);
ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "two Thread-" + index);
return t;
}
});
executorService.execute(() -> {
try {
new TestSync().simpleSync();
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
And this is the print result:
create no 1 thread
sleep 1000
Producer trying to get LOCK_OBJECT lock
Producer get LOCK_OBJECT lock
sleep 3000
create no 2 thread
Consumer trying to get LOCK_OBJECT lock
Consumer get LOCK_OBJECT lock
Consumer release LOCK_OBJECT lock
full!
The code in your question does not compile. What is Print
? It appears twice in your code. Once in method main
Print.sleep(1000);
In the below code, I simply created a class named Print
and defined a static method sleep
.
Locks work on objects that are shared between threads. In your code you create a separate TestSync
object for each thread. Hence no shared objects. Try creating one instance of TestSync
and send it to both threads. Also, you don't need a separate ExecutorService
for each thread. You can use a single ExecutorService
to launch many threads. The below code demonstrates.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class TestSync {
private volatile Integer amount = 0;
private final Object LOCK_OBJECT = new Object();
private final Object FULL = new Object();
public void doubleSync() throws InterruptedException {
System.out.println("Producer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Producer get LOCK_OBJECT lock ");
Print.sleep(3000);
while (amount >= 0) {
synchronized (FULL) {
System.out.println("full!");
FULL.wait();
}
}
System.out.println("continue~");
amount++;
}
}
public void simpleSync() {
System.out.println("Consumer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Consumer get LOCK_OBJECT lock");
}
System.out.println("Consumer release LOCK_OBJECT lock");
}
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
ExecutorService threadPool = Executors.newFixedThreadPool(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "Thread-" + index);
return t;
}
});
TestSync ts = new TestSync();
threadPool.execute(() -> {
try {
ts.doubleSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Print.sleep(1000);
threadPool.execute(() -> {
try {
ts.simpleSync();
} catch (Exception e) {
e.printStackTrace();
}
});
threadPool.shutdown();
}
}
class Print {
public static void sleep(long interval) {
System.out.println("sleep " + interval);
}
}
Note that it is recommended to call method shutdown()
, of interface ExecutorService
, after you have submitted all your tasks.
Here is the output when I run the above code.
create no 1 thread
Producer trying to get LOCK_OBJECT lock
Producer get LOCK_OBJECT lock
sleep 1000
create no 2 thread
Consumer trying to get LOCK_OBJECT lock
sleep 3000
full!
As you can see, the consumer does not obtain the lock.