From d4c7cc1b34141fbac7bcd798b0fb971f530fddd9 Mon Sep 17 00:00:00 2001 From: Diego Ramos Date: Fri, 5 Oct 2018 06:38:44 -0500 Subject: [PATCH] Added semaphore examples --- .../Semaphores/java/Semaphores/Semaphore.java | 35 +++++++++++ .../java/Semaphores/multiplex/Multiplex.java | 37 +++++++++++ .../Semaphores/multiplex/MultiplexThread.java | 14 +++++ .../java/Semaphores/mutex/Mutex.java | 61 +++++++++++++++++++ .../java/Semaphores/mutex/MutexThread.java | 36 +++++++++++ .../Semaphores/rendezVouz/RendezVouz.java | 60 ++++++++++++++++++ .../rendezVouz/RendezVouzThread.java | 39 ++++++++++++ .../java/Semaphores/signaling/Signaling.java | 59 ++++++++++++++++++ .../Semaphores/signaling/SignalingThread.java | 26 ++++++++ 9 files changed, 367 insertions(+) create mode 100644 Concurrency/Semaphores/java/Semaphores/Semaphore.java create mode 100644 Concurrency/Semaphores/java/Semaphores/multiplex/Multiplex.java create mode 100644 Concurrency/Semaphores/java/Semaphores/multiplex/MultiplexThread.java create mode 100644 Concurrency/Semaphores/java/Semaphores/mutex/Mutex.java create mode 100644 Concurrency/Semaphores/java/Semaphores/mutex/MutexThread.java create mode 100644 Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouz.java create mode 100644 Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouzThread.java create mode 100644 Concurrency/Semaphores/java/Semaphores/signaling/Signaling.java create mode 100644 Concurrency/Semaphores/java/Semaphores/signaling/SignalingThread.java diff --git a/Concurrency/Semaphores/java/Semaphores/Semaphore.java b/Concurrency/Semaphores/java/Semaphores/Semaphore.java new file mode 100644 index 00000000..7e672f7f --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/Semaphore.java @@ -0,0 +1,35 @@ +package Semaphores; + +/** + * Although java.util.concurrent has its own semaphore class, this is a simpler implementation of a semaphore + */ +public class Semaphore { + + /** + * Semaphore's count, it represent how many threads can access the resource at the same time + */ + private int count; + + public Semaphore(int count) { + this.count = count; + } + + public synchronized void acquire() { + count--; + if(count < 0) { + try { + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public synchronized void release() { + count++; + if(count <= 0) { + notify(); + } + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/multiplex/Multiplex.java b/Concurrency/Semaphores/java/Semaphores/multiplex/Multiplex.java new file mode 100644 index 00000000..2af09a35 --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/multiplex/Multiplex.java @@ -0,0 +1,37 @@ +package Semaphores.multiplex; + +import Semaphores.Semaphore; + +public class Multiplex { + + static Semaphore semaphore; + + public static void main(String args[]) { + new Multiplex(); + MultiplexThread[] threads = new MultiplexThread[50]; + for(int i = 0; i < threads.length; i++){ + threads[i] = new MultiplexThread(); + } + for(MultiplexThread thread : threads) { + thread.start(); + } + } + + public Multiplex() { + //This semaphore ensures that a maximum of three threads are using the resource at the same time + semaphore = new Semaphore(3); + } + + /** + * You want to limit access to this method with the semaphore + */ + public static void a() { + try { + System.out.println("calling a"); + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/multiplex/MultiplexThread.java b/Concurrency/Semaphores/java/Semaphores/multiplex/MultiplexThread.java new file mode 100644 index 00000000..6420e10f --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/multiplex/MultiplexThread.java @@ -0,0 +1,14 @@ +package Semaphores.multiplex; + +public class MultiplexThread extends Thread { + + public MultiplexThread() { + } + + public void run() { + //Before calling the method, the thread acquires the permit, after calling it, it releases it. + Multiplex.semaphore.acquire(); + Multiplex.a(); + Multiplex.semaphore.release(); + } +} diff --git a/Concurrency/Semaphores/java/Semaphores/mutex/Mutex.java b/Concurrency/Semaphores/java/Semaphores/mutex/Mutex.java new file mode 100644 index 00000000..e83aa68f --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/mutex/Mutex.java @@ -0,0 +1,61 @@ +package Semaphores.mutex; + +import Semaphores.Semaphore; + +public class Mutex { + + /** + * This is the resource you want to limit access to + */ + private static int n; + + static Semaphore semaphore; + + public static void main(String[] args) { + + new Mutex(); + MutexThread a = new MutexThread(10, MutexThread.TYPE_A); + MutexThread b = new MutexThread(10, MutexThread.TYPE_B); + + //This starts the two threads randomly every time you run the program + int order = (int) (Math.random() * 100) % 2; + + if (order == 0) { + System.out.println("A starts"); + a.start(); + b.start(); + } else { + System.out.println("B starts"); + b.start(); + a.start(); + } + } + + public Mutex() { + n = 0; + semaphore = new Semaphore(1); //A mutex semaphore always has a count of 1 + } + + //Methods a and b operate the variable in different ways + + public static void a() { + n += 1000; + try { + System.out.println(n); + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public static void b() { + n ++; + try { + System.out.println(n); + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/mutex/MutexThread.java b/Concurrency/Semaphores/java/Semaphores/mutex/MutexThread.java new file mode 100644 index 00000000..39a57c34 --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/mutex/MutexThread.java @@ -0,0 +1,36 @@ +package Semaphores.mutex; + +public class MutexThread extends Thread { + + private int times; + + private int type; + + public final static int TYPE_A = 1; + + public final static int TYPE_B = 0; + + + public MutexThread(int veces, int llamar ) { + this.times = veces; + this.type = llamar; + } + + public void run() { + if(type == TYPE_A) { + for(int i = 0; i < times; i++){ + Mutex.semaphore.acquire(); + Mutex.a(); + Mutex.semaphore.release(); + } + } + if(type == TYPE_B) { + for(int i = 0; i < times; i++){ + Mutex.semaphore.acquire(); + Mutex.b(); + Mutex.semaphore.release(); + } + } + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouz.java b/Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouz.java new file mode 100644 index 00000000..f65685ee --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouz.java @@ -0,0 +1,60 @@ +package Semaphores.rendezVouz; + +import Semaphores.Semaphore; + +/** + * You use semaphores this way when you want methods in different threads to happen in a certain order + */ +public class RendezVouz { + + /** + * In the end, n = ((3*8) + (4*7))/2 = 26 + */ + private static int n; + + static Semaphore s1; + + static Semaphore s2; + + + public static void main(String args[]) { + new RendezVouz(); + RendezVouzThread a = new RendezVouzThread(RendezVouzThread.TYPE_A); + RendezVouzThread b = new RendezVouzThread(RendezVouzThread.TYPE_B); + + int order = (int) (Math.random() * 100) % 2; + if (order == 0) { + System.out.println("B starts"); + a.start(); + b.start(); + } else { + System.out.println("A starts"); + b.start(); + a.start(); + } + } + + public RendezVouz() { + n = 0; + //In this case, semaphores start in 0, you want them to lock the first thread that calls acquire() + s1 = new Semaphore(0); + s2 = new Semaphore(0); + } + + public static void xA() { + n += 3*8; + } + + public static void xB() { + n += 4*7; + } + + public static void yA() { + System.out.println(n); + } + + public static void yB() { + n = n/2; + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouzThread.java b/Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouzThread.java new file mode 100644 index 00000000..b0d9c337 --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/rendezVouz/RendezVouzThread.java @@ -0,0 +1,39 @@ +package Semaphores.rendezVouz; + +public class RendezVouzThread extends Thread { + + private int type; + + public final static int TYPE_A = 1; + + public final static int TYPE_B = 0; + + public RendezVouzThread(int type ) { + this.type = type; + } + + + @Override + public void run() { + /* + * xA() and xB() can be called in any order, so each threads calls the one it corresponds to them first. Then, + * one of the thread calls release() on one of the semaphores, so when the other one calls acquire() it doesn't + * block. Then, the first thread calls acquire() on the other semaphore to wait for the other thread. Finally, + * the second thread calls release() on the semaphore that the firs thread is blocked. This way, yB() is always + * called before yA(). Independently of the order that the threads started + */ + if(type == TYPE_A){ + RendezVouz.xA(); + RendezVouz.s1.release(); + RendezVouz.s2.acquire(); + RendezVouz.yA(); + } + else if(type == TYPE_B){ + RendezVouz.xB(); + RendezVouz.s1.acquire(); + RendezVouz.yB(); + RendezVouz.s2.release(); + } + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/signaling/Signaling.java b/Concurrency/Semaphores/java/Semaphores/signaling/Signaling.java new file mode 100644 index 00000000..9955d163 --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/signaling/Signaling.java @@ -0,0 +1,59 @@ +package Semaphores.signaling; + +import Semaphores.Semaphore; + +/** + * You can also use semaphores when you have a method that you always want to call before another. + */ +public class Signaling { + + public static double n; + + static Semaphore semaphore; + + public static void main(String[] args) { + + new Signaling(); + SignalingThread a = new SignalingThread(SignalingThread.TYPE_A); + SignalingThread b = new SignalingThread(SignalingThread.TYPE_B); + + int orden = (int) (Math.random() * 100) % 2; + + if (orden == 0) { + System.out.println("A starts"); + a.start(); + b.start(); + } else { + System.out.println("B starts"); + b.start(); + a.start(); + } + + } + + public Signaling() { + n = 0; + semaphore = new Semaphore(0); //You want the first thread to call acquire() to block; + } + + //In this case, you always want a to be called before b to avoid getting an exception. + + public static void a() { + n = 2; + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public static void b() { + System.out.println(0 / n); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/Concurrency/Semaphores/java/Semaphores/signaling/SignalingThread.java b/Concurrency/Semaphores/java/Semaphores/signaling/SignalingThread.java new file mode 100644 index 00000000..5c05d848 --- /dev/null +++ b/Concurrency/Semaphores/java/Semaphores/signaling/SignalingThread.java @@ -0,0 +1,26 @@ +package Semaphores.signaling; + +public class SignalingThread extends Thread { + + private int type; + + public final static int TYPE_A = 1; + + public final static int TYPE_B = 0; + + public SignalingThread(int tipo) { + this.type = tipo; + } + + public void run() { + //As you always want a() to be called first, the thread that calls it releases the permit after calling a. + if(type == TYPE_A) { + Signaling.a(); + Signaling.semaphore.release(); + } + if(type == TYPE_B) { + Signaling.semaphore.acquire(); + Signaling.b(); + } + } +}