|
| 1 | +package concurrent.shared; |
| 2 | + |
| 3 | +import java.util.concurrent.*; |
| 4 | + |
| 5 | +/** |
| 6 | + * 目的,在添加数据操作需要互斥、全部任务为读取时是线程安全的情况下, |
| 7 | + * 可以使用Semaphore的公平锁来提高吞吐量,而非使用互斥锁。思路是读取时 |
| 8 | + * 仅仅获取一个许可,而添加数据时获取全部许可。 |
| 9 | + * |
| 10 | + * 注意: |
| 11 | + * 没有获取许可也能释放许可—相应的statu+1。但是释放后的总许可数量不能超过Integer.MAX_VALUE; |
| 12 | + * int next = current + releases; |
| 13 | + * if (next < current) // overflow |
| 14 | + * throw new Error("Maximum permit count exceeded"); |
| 15 | + * |
| 16 | + * 结论:ok |
| 17 | + * |
| 18 | + * @author 杜艮魁 |
| 19 | + * @date 2018/10/9 |
| 20 | + */ |
| 21 | +public class SemaphoreTest { |
| 22 | + /** |
| 23 | + * 注意一定要用公平锁,非公平锁在高并发情况下会导致put任务难以执行 |
| 24 | + */ |
| 25 | + private static final Semaphore sem = new Semaphore(Integer.MAX_VALUE, true); |
| 26 | + |
| 27 | + public static void main(String[] args) throws InterruptedException { |
| 28 | + |
| 29 | +// 结论1 |
| 30 | +// sem.release(); |
| 31 | +// System.out.println(sem.availablePermits()); |
| 32 | + |
| 33 | + /** |
| 34 | + * 需一个许可的读取任务 |
| 35 | + */ |
| 36 | + Runnable getTask = () -> { |
| 37 | + try { |
| 38 | + sem.acquire();//默认获取一个许可 |
| 39 | + for (int i = 0; i < 5; i++) { |
| 40 | + System.out.println("getting data " + Thread.currentThread().getName() + "..."+i); |
| 41 | + TimeUnit.SECONDS.sleep(1); |
| 42 | + } |
| 43 | + } catch (InterruptedException e) { |
| 44 | + } finally { |
| 45 | + sem.release(); |
| 46 | + } |
| 47 | + }; |
| 48 | + |
| 49 | + /** |
| 50 | + * 需全部Integer.MAX_VALUE许可的添加数据任务 |
| 51 | + */ |
| 52 | + Runnable putTask = () -> { |
| 53 | + try { |
| 54 | + sem.acquire(Integer.MAX_VALUE); |
| 55 | + for (int i = 0; i < 5; i++) { |
| 56 | + System.out.println("putting data " + Thread.currentThread().getName() + "..."+i); |
| 57 | + TimeUnit.SECONDS.sleep(1); |
| 58 | + } |
| 59 | + } catch (InterruptedException e) { |
| 60 | + } finally { |
| 61 | + sem.release(Integer.MAX_VALUE); |
| 62 | + } |
| 63 | + }; |
| 64 | + |
| 65 | + |
| 66 | + /** |
| 67 | + * 模拟这种情形,前两个线程并发执行读取任务,第三个线程put阻塞,此时第四个任务也会阻塞,会等待第三个任务执行结束后再执行 |
| 68 | + */ |
| 69 | + ExecutorService es= Executors.newCachedThreadPool(); |
| 70 | + es.submit(getTask); |
| 71 | + TimeUnit.MILLISECONDS.sleep(10); |
| 72 | + |
| 73 | + es.submit(getTask); |
| 74 | + TimeUnit.MILLISECONDS.sleep(10); |
| 75 | + |
| 76 | + es.submit(putTask); |
| 77 | + TimeUnit.MILLISECONDS.sleep(10); |
| 78 | + |
| 79 | + es.submit(getTask); |
| 80 | + |
| 81 | + es.shutdown(); |
| 82 | + } |
| 83 | +} |
0 commit comments