Using the synchronized
keyword to protect a block of code, we must use an object reference as a parameter.
We can use the this
keyword to reference the object that executes the method.
Or we can use other object references.
Normally, we have to create objects exclusively with this purpose.
JVM guarantees that only one thread can have access to the protected code.
public class Main { public static void main(String[] args) { SharedResource cinema = new SharedResource(); Consumer1 consumer1 = new Consumer1(cinema); Thread thread1 = new Thread(consumer1, "consumer1"); // Creates a consumer2 and a Thread to run it Consumer2 consumer2 = new Consumer2(cinema); Thread thread2 = new Thread(consumer2, "consumer2"); // Starts the threads thread1.start();//from w w w. j av a 2 s . co m thread2.start(); try { // Waits for the finalization of the threads thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // Print the vacancies in the cinemas System.out.printf("Room 1 Vacancies: %d\n", cinema.getVacancies1()); System.out.printf("Room 2 Vacancies: %d\n", cinema.getVacancies2()); } } class SharedResource { private long vacancies1; private long vacancies2; private final Object control1, control2; public SharedResource() { control1 = new Object(); control2 = new Object(); vacancies1 = 20; vacancies2 = 20; } public boolean sellTickets1(int number) { synchronized (control1) { if (number < vacancies1) { vacancies1 -= number; return true; } else { return false; } } } public boolean sellTickets2(int number) { synchronized (control2) { if (number < vacancies2) { vacancies2 -= number; return true; } else { return false; } } } public boolean returnTickets1(int number) { synchronized (control1) { vacancies1 += number; return true; } } public boolean returnTickets2(int number) { synchronized (control2) { vacancies2 += number; return true; } } public long getVacancies1() { return vacancies1; } public long getVacancies2() { return vacancies2; } } class Consumer1 implements Runnable { private SharedResource shapedData; public Consumer1(SharedResource cinema) { this.shapedData = cinema; } @Override public void run() { shapedData.sellTickets1(3); shapedData.sellTickets1(2); shapedData.sellTickets2(2); shapedData.returnTickets1(3); shapedData.sellTickets1(5); shapedData.sellTickets2(2); shapedData.sellTickets2(2); shapedData.sellTickets2(2); } } class Consumer2 implements Runnable { private SharedResource shapedData; public Consumer2(SharedResource cinema) { this.shapedData = cinema; } @Override public void run() { shapedData.sellTickets2(2); shapedData.sellTickets2(4); shapedData.sellTickets1(2); shapedData.sellTickets1(1); shapedData.returnTickets2(2); shapedData.sellTickets1(3); shapedData.sellTickets2(2); shapedData.sellTickets1(2); } }