Java: Semaphore is used to protect access to multiple shared resources. semaphore shares resources.
The semaphore mechanism is a common synchronization mechanism, which is widely used in modern OS. Semaphore is a non-zero value. When its value is greater than 0, it indicates that the system still has enough resources allocated to the request thread. Each time a resource is allocated, the value decreases. If the value is equal to 0, no resources can be allocated. JDK providesSemaphore
Class.
If we have a total of three printers available, there are currently N threads requesting the use of printers, to achieve access protection for printer resources, there are two ways:
Obviously, when only one thread can use the printer at a certain time point, the other two printer resources will be wasted. Some may think that if you only lock the code for checking and assigning the printer, but do not lock the printer, when the first thread uses the printer, the second thread can still request the printer. can I allow the three threads to use the printer?
This is very dangerous. We call it a resource.Escape. If the printer is not locked, if the request thread allocates the escaped printer to other threads, the thread synchronization will be meaningless.
For method 2, when thread A uses the printer, thread B can still request and use the printer, and thread C can also. After thread A is used up, semaphore must be released so that other threads can use this printer again.
First, define the printer object:
class Printer { private String name; private int index; public Printer(String name, int index) { this.name = name; this.index = index; } public void print() { System.out.println("printer " + name + " is working for " + Thread.currentThread().getName()); try { Thread.currentThread().sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("printer " + name + " for " + Thread.currentThread().getName() + " is done"); } public int getIndex() { return this.index; }}
Then, we define a printer Pool ). Use this pool to securely allocate printer resources:
class PrinterPool { /** * store all available devices */ private Printer[] printers; private boolean[] freePrinters; private Lock lock = new ReentrantLock(); /** * create a semaphore for 3 resources */ private Semaphore semaphore = new Semaphore(3); /** * 3 printers available in this pool. */ public PrinterPool() { printers = new Printer[] { new Printer("A", 0), new Printer("B", 1), new Printer("C", 2) }; freePrinters = new boolean[] { true, true, true }; } /** * use printer */ public Printer printData() { Printer printer = null; try { semaphore.acquire(); while (true) { printer = getFreePrinter(); if (printer != null) { break; } } // use printer printer.print(); // reclaim printer reclaimPrinter(printer); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } return printer; } private Printer getFreePrinter() { Printer printer = null; lock.lock(); for (int ix = 0 ; ix < freePrinters.length ; ++ix) { if (true == freePrinters[ix]) { freePrinters[ix] = false; printer = printers[ix]; break; } } lock.unlock(); return printer; } private void reclaimPrinter(Printer p) { lock.lock(); this.freePrinters[p.getIndex()] = true; lock.unlock(); }}
Finally, write the test code and start 10 threads to request the printer:
// create printer pool PrinterPool pool = new PrinterPool(); Runnable job = () -> { pool.printData(); }; // create 10 threads Thread[] threads = new Thread[10]; for (int ix = 0 ; ix < 10 ; ++ix) { threads[ix] = new Thread(job); } // start all threads for (int ix = 0 ; ix < 10 ; ++ix) { threads[ix].start(); }
Output result: