fork download
  1. import java.util.concurrent.CountDownLatch;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.Semaphore;
  5. import java.util.concurrent.TimeUnit;
  6.  
  7. class IdeOne {
  8.  
  9. private static final Semaphore lock = new Semaphore(Integer.MAX_VALUE, true);
  10.  
  11. public static void doReadLocked(final CountDownLatch latch) throws InterruptedException {
  12. lock.acquire();
  13. try {
  14. // Do some read locked stuff
  15. System.out.println("READ LOCK");
  16. latch.countDown();
  17. latch.await();
  18. } finally {
  19. lock.release();
  20. System.out.println("RELEASE READ");
  21. }
  22. }
  23.  
  24. public static void doWriteLocked(final CountDownLatch latch) throws InterruptedException {
  25. lock.acquire(Integer.MAX_VALUE);
  26. try {
  27. System.out.println("WRITE LOCK");
  28. latch.countDown();
  29. latch.await();
  30. // Do write locked stuff
  31. } finally {
  32. lock.release(Integer.MAX_VALUE);
  33. System.out.println("RELEASE WRITE");
  34. }
  35. }
  36.  
  37. public static void main(final String[] args) throws InterruptedException {
  38. final ExecutorService executorService = Executors.newFixedThreadPool(5);
  39.  
  40. final CountDownLatch latch = new CountDownLatch(3);
  41.  
  42. executorService.submit(() -> {
  43. try {
  44. doReadLocked(latch);
  45. } catch (InterruptedException e) {
  46. e.printStackTrace();
  47. }
  48. });
  49. executorService.submit(() -> {
  50. try {
  51. doReadLocked(latch);
  52. } catch (InterruptedException e) {
  53. e.printStackTrace();
  54. }
  55. });
  56.  
  57. // At this point there are 2 readers, so the write lock will be queued.
  58. final CountDownLatch writeLatch = new CountDownLatch(2);
  59. executorService.submit(() -> {
  60. try {
  61. doWriteLocked(writeLatch);
  62. } catch (InterruptedException e) {
  63. e.printStackTrace();
  64. }
  65. });
  66.  
  67. System.out.println("(2) WRITE COUNT = " + writeLatch.getCount());
  68.  
  69. // Give time to ensure that the write has been submitted.
  70. TimeUnit.SECONDS.sleep(1L);
  71.  
  72. final CountDownLatch finalReadLatch = new CountDownLatch(1);
  73. // Before releasing the write, submit another read lock.
  74. executorService.submit(() -> {
  75. try {
  76. System.out.println("Submitting READ");
  77. doReadLocked(finalReadLatch);
  78. } catch (InterruptedException e) {
  79. e.printStackTrace();
  80. }
  81. });
  82.  
  83. TimeUnit.SECONDS.sleep(1L);
  84.  
  85. System.out.println("(1) READ COUNT = " + finalReadLatch.getCount());
  86.  
  87. // Free up all the first ones queued.
  88. latch.countDown();
  89.  
  90. // Give write lock time to start...
  91. TimeUnit.SECONDS.sleep(1L);
  92.  
  93. System.out.println("(1) WRITE COUNT = " + writeLatch.getCount());
  94. System.out.println("(1) READ COUNT = " + finalReadLatch.getCount());
  95.  
  96. // Release the writer and give final reader time to start up...
  97. writeLatch.countDown();
  98. TimeUnit.SECONDS.sleep(1L);
  99.  
  100. System.out.println("(0) READ COUNT = " + finalReadLatch.getCount());
  101.  
  102. executorService.shutdown();
  103. TimeUnit.SECONDS.sleep(1L);
  104. }
  105. }
  106.  
Success #stdin #stdout 0.14s 59152KB
stdin
Standard input is empty
stdout
READ LOCK
READ LOCK
(2) WRITE COUNT = 2
Submitting READ
(1) READ COUNT = 1
RELEASE READ
WRITE LOCK
RELEASE READ
(1) WRITE COUNT = 1
(1) READ COUNT = 1
RELEASE WRITE
READ LOCK
RELEASE READ
(0) READ COUNT = 0