diff --git a/.gitignore b/.gitignore
index 80b6c36650ad493d5e9d4fa1b3268cb12abaca62..3ba5e2fd043b42aaf3913030c1df2e77dc9bc660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,33 @@
+*.DS_Store
+/*/*.DS_Store
+
+/*/bin/
+/*/target/
+/*/build/
+bin/
+target/
+build/
+logs/
+
+/*/logs/
+.idea/
+/*/.idea/
+/*/*.iml
+*.iml
+
+/*/*.classpath
+*.classpath
+/*/.settings/
+/*/*/.settings/
+/*/.project
+.project
+
# Compiled class file
*.class
# Log file
*.log
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
# Package Files #
*.jar
*.war
@@ -18,8 +36,6 @@
*.zip
*.tar.gz
*.rar
-*.idea
-./target
-*.iml
+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
diff --git a/pom.xml b/pom.xml
index 568faf31f72e08022adeb2e8a0860ea45fd02d5c..7d06bec20f2f2b2418436d37286260b2f171d083 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
org.idea
- concurrence-programming-lession
+ juc-programming
1.0-SNAPSHOT
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21305/Condition\346\241\210\344\276\213/ConditionDemo_1.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/Condition\346\241\210\344\276\213/ConditionDemo_1.java"
similarity index 97%
rename from "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21305/Condition\346\241\210\344\276\213/ConditionDemo_1.java"
rename to "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/Condition\346\241\210\344\276\213/ConditionDemo_1.java"
index 12e0c4c4dd0627d8fb5276ff472bd8bc67782c3c..a2dfb8dcfdeab4cf396b82e96449939b349749cb 100644
--- "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21305/Condition\346\241\210\344\276\213/ConditionDemo_1.java"
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/Condition\346\241\210\344\276\213/ConditionDemo_1.java"
@@ -1,4 +1,4 @@
-package 并发编程05.Condition案例;
+package 并发编程.demo.Condition案例;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CountDownLatch\346\241\210\344\276\213/CountDownLatchTest.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CountDownLatch\346\241\210\344\276\213/CountDownLatchTest.java"
new file mode 100644
index 0000000000000000000000000000000000000000..cc395e689ee45a8b06aea80f7d88c14414f50872
--- /dev/null
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CountDownLatch\346\241\210\344\276\213/CountDownLatchTest.java"
@@ -0,0 +1,47 @@
+package 并发编程.demo.CountDownLatch案例;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * 场景1 让多个线程等待:模拟并发,让并发线程一起执行
+ *
+ * CountDownLatch应用场景
+ * CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。
+ * CountDownLatch的两种使用场景:
+ * 场景1:让多个线程等待
+ * 场景2:让单个线程等待。
+ *
+ * CountDownLatch实现原理
+ * 底层基于 AbstractQueuedSynchronizer 实现,CountDownLatch 构造函数中指定的count直接赋给AQS的state;每次countDown()则都是release(1)减1,最后减到0时unpark阻塞线程;这一步是由最后一个执行countdown方法的线程执行的。
+ * 而调用await()方法时,当前线程就会判断state属性是否为0,如果为0,则继续往下执行,如果不为0,则使当前线程进入等待状态,直到某个线程将state属性置为0,其就会唤醒在await()方法中等待的线程。
+ *
+ * CountDownLatch与Thread.join的区别
+ * CountDownLatch的作用就是允许一个或多个线程等待其他线程完成操作,看起来有点类似join() 方法,但其提供了比 join() 更加灵活的API。
+ * CountDownLatch可以手动控制在n个线程里调用n次countDown()方法使计数器进行减一操作,也可以在一个线程里调用n次执行减一操作。
+ * 而 join() 的实现原理是不停检查join线程是否存活,如果 join 线程存活则让当前线程永远等待。所以两者之间相对来说还是CountDownLatch使用起来较为灵活。
+ */
+public class CountDownLatchTest {
+
+
+ public static void main(String[] args) throws InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ System.out.println("比赛开始");
+ for (int i = 0; i < 5; i++) {
+ Thread.sleep(1000);
+ new Thread(() -> {
+ try {
+ String partner = "【" + Thread.currentThread().getName() + "】";
+ System.out.println(partner + "准备就绪……");
+ //准备完毕……运动员都阻塞在这,等待号令
+ countDownLatch.await();
+ System.out.println(partner + "开跑!");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ },"运动员" + i+1).start();
+ }
+
+ Thread.sleep(2000);// 裁判准备发令
+ countDownLatch.countDown();// 发令枪:执行发令
+ }
+}
\ No newline at end of file
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CountDownLatch\346\241\210\344\276\213/CountDownLatchTest2.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CountDownLatch\346\241\210\344\276\213/CountDownLatchTest2.java"
new file mode 100644
index 0000000000000000000000000000000000000000..c17c2905cbacecfe96d68d70a27ecfc298d27822
--- /dev/null
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CountDownLatch\346\241\210\344\276\213/CountDownLatchTest2.java"
@@ -0,0 +1,37 @@
+package 并发编程.demo.CountDownLatch案例;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 场景2 让单个线程等待:多个线程(任务)完成后,进行汇总合并
+ * 一个车能做5个乘客。司机必须等到5个乘客都上车之后才能发车
+ *
+ * 很多时候,我们的并发任务,存在前后依赖关系;比如数据详情页需要同时调用多个接口获取数据,并发请求获取到数据后、需要进行结果合并;
+ * 或者多个数据操作完成后,需要数据check;这其实都是:在多个线程(任务)完成后,进行汇总合并的场景。
+ */
+public class CountDownLatchTest2 {
+
+ public static void main(String[] args) throws Exception {
+
+ // 一个车能做5个乘客。司机必须等到5个乘客都上车之后才能发车
+ CountDownLatch countDownLatch = new CountDownLatch(5);
+ for (int i = 0; i < 5; i++) {
+ final int index = i+1;
+ Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(1000));
+ new Thread(() -> {
+ try {
+ System.out.println("【"+Thread.currentThread().getName()+"】已上车");
+ countDownLatch.countDown();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ },"乘客" + index).start();
+ }
+ // 主线程在阻塞,当计数器==0,就唤醒主线程往下执行。
+ countDownLatch.await();
+ // 即:所有乘客都上车之后才发车
+ System.out.println("【发车!】");
+
+ }
+}
\ No newline at end of file
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierDemo.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierDemo.java"
similarity index 96%
rename from "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierDemo.java"
rename to "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierDemo.java"
index 5c23dead7c2ed61475b42ce56b45b7b50d28f2f8..5a9a521ec50884cdae70c26f5d20fd521b1a6f98 100644
--- "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierDemo.java"
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierDemo.java"
@@ -1,4 +1,4 @@
-package 并发编程10.CyclicBarrier案例;
+package 并发编程.demo.CyclicBarrier案例;
import java.util.ArrayList;
import java.util.List;
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierTest1.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierTest1.java"
new file mode 100644
index 0000000000000000000000000000000000000000..16b1a49e946298816c42bc1ae1e815135db37044
--- /dev/null
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierTest1.java"
@@ -0,0 +1,60 @@
+package 并发编程.demo.CyclicBarrier案例;
+
+import java.util.Set;
+import java.util.concurrent.*;
+
+/**
+ * CyclicBarrier介绍
+ * 字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
+ *
+ * 构造方法 public CyclicBarrier(int parties) parties表示屏障拦截的线程数量,每个线程调用 await 方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。
+ * 用于在线程到达屏障时,优先执行 barrierAction,方便处理更复杂的业务场景(该线程的执行时机是在到达屏障之后再执行)
+ *
+ * CyclicBarrier应用场景:
+ * CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的场景。
+ */
+public class CyclicBarrierTest1 {
+
+ //保存每个学生的平均成绩
+ private ConcurrentHashMap map = new ConcurrentHashMap();
+
+ private ExecutorService threadPool = Executors.newFixedThreadPool(3);
+
+ private CyclicBarrier cb = new CyclicBarrier(3, () -> {
+ int result = 0;
+ Set set = map.keySet();
+ for (String s : set) {
+ result += map.get(s);
+ }
+ System.out.println("三人平均成绩为:" + (result / 3) + "分");
+ });
+
+
+ public void count() {
+ for (int i = 0; i < 3; i++) {
+ threadPool.execute(new Runnable() {
+
+ @Override
+ public void run() {
+ //获取学生平均成绩
+ int score = (int) (Math.random() * 40 + 60);
+ map.put(Thread.currentThread().getName(), score);
+ System.out.println(Thread.currentThread().getName()
+ + "同学的平均成绩为:" + score);
+ try {
+ //执行完运行await(),等待所有学生平均成绩都计算完毕
+ cb.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ }
+
+ });
+ }
+ }
+
+ public static void main(String[] args) {
+ CyclicBarrierTest1 cb = new CyclicBarrierTest1();
+ cb.count();
+ }
+}
\ No newline at end of file
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierTest2.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierTest2.java"
new file mode 100644
index 0000000000000000000000000000000000000000..974cdfb47243998771bfcc36b4a3f002cc934e5f
--- /dev/null
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/CyclicBarrierTest2.java"
@@ -0,0 +1,66 @@
+package 并发编程.demo.CyclicBarrier案例;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 利用CyclicBarrier的计数器能够重置,屏障可以重复使用的特性,可以支持类似“人满发车”的场景(重复)
+ * 一次性的"人满发车"场景可以使用CountDownLatch 实现
+ *
+ * CyclicBarrier与CountDownLatch的区别
+ * CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次
+ * CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法。
+ * CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。
+ * CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同。CountDownLatch一般用于一个或多个线程,等待其他线程执行完任务后,再执行。CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行。
+ * CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果。
+ * CyclicBarrier是通过ReentrantLock的"独占锁"和Conditon来实现一组线程的阻塞唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现
+ *
+ * CyclicBarrier源码分析
+ * 关注点:
+ * 1.一组线程在触发屏障之前互相等待,最后一个线程到达屏障后唤醒逻辑是如何实现的
+ * 2.删栏循环使用是如何实现的
+ * 3.条件队列到同步队列的转换实现逻辑
+ */
+public class CyclicBarrierTest2 {
+
+ public static void main(String[] args) {
+
+ AtomicInteger counter = new AtomicInteger();
+ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
+ 5, 5, 1000, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<>(100),
+ (r) -> new Thread(r, counter.addAndGet(1) + " 号 "),
+ new ThreadPoolExecutor.AbortPolicy());
+
+ CyclicBarrier cyclicBarrier = new CyclicBarrier(5,
+ () -> System.out.println("裁判:比赛开始~~"));
+
+ for (int i = 0; i < 10; i++) {
+ threadPoolExecutor.submit(new Runner(cyclicBarrier));
+ }
+
+ }
+
+ static class Runner extends Thread {
+ private CyclicBarrier cyclicBarrier;
+
+ public Runner(CyclicBarrier cyclicBarrier) {
+ this.cyclicBarrier = cyclicBarrier;
+ }
+
+ @Override
+ public void run() {
+ try {
+ int sleepMills = ThreadLocalRandom.current().nextInt(1000);
+ Thread.sleep(sleepMills);
+ System.out.println(Thread.currentThread().getName() + " 选手已就位, 准备共用时: " + sleepMills + "ms" + cyclicBarrier.getNumberWaiting());
+ cyclicBarrier.await();
+
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/CyclicBarrier\346\241\210\344\276\213/MultiRequestHandler.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/MultiRequestHandler.java"
similarity index 93%
rename from "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/CyclicBarrier\346\241\210\344\276\213/MultiRequestHandler.java"
rename to "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/MultiRequestHandler.java"
index f969031a06ca63d997d628eee5f1352f9730d3bc..0b91ae9c077ece7550b1b3aae789950ef16538e0 100644
--- "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/CyclicBarrier\346\241\210\344\276\213/MultiRequestHandler.java"
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/CyclicBarrier\346\241\210\344\276\213/MultiRequestHandler.java"
@@ -1,6 +1,5 @@
-package 并发编程10.CyclicBarrier案例;
+package 并发编程.demo.CyclicBarrier案例;
-import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21304/ReentrantLock\346\241\210\344\276\213/LockCompareDemo.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/ReentrantLock\346\241\210\344\276\213/LockCompareDemo.java"
similarity index 97%
rename from "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21304/ReentrantLock\346\241\210\344\276\213/LockCompareDemo.java"
rename to "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/ReentrantLock\346\241\210\344\276\213/LockCompareDemo.java"
index 39a6e366fe666a9c4341d802e68e3187d9877d1b..ba494abdbcea21b166826ae3895f13e786023257 100644
--- "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21304/ReentrantLock\346\241\210\344\276\213/LockCompareDemo.java"
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/ReentrantLock\346\241\210\344\276\213/LockCompareDemo.java"
@@ -1,4 +1,4 @@
-package 并发编程04.ReentrantLock案例;
+package 并发编程.demo.ReentrantLock案例;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
diff --git "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/Semaphore\346\241\210\344\276\213/BlockQueue.java" "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/Semaphore\346\241\210\344\276\213/BlockQueue.java"
similarity index 86%
rename from "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/Semaphore\346\241\210\344\276\213/BlockQueue.java"
rename to "src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/Semaphore\346\241\210\344\276\213/BlockQueue.java"
index f5d1bc5c32da8328a92f7763cbd31eed6ba4c5b5..489edc5f18389978690b8af4fe67efeecc7cad79 100644
--- "a/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\21310/Semaphore\346\241\210\344\276\213/BlockQueue.java"
+++ "b/src/main/java/\345\271\266\345\217\221\347\274\226\347\250\213/demo/Semaphore\346\241\210\344\276\213/BlockQueue.java"
@@ -1,4 +1,4 @@
-package 并发编程10.Semaphore案例;
+package 并发编程.demo.Semaphore案例;
import java.util.ArrayList;
import java.util.List;
@@ -12,22 +12,19 @@ import java.util.concurrent.TimeUnit;
*/
public class BlockQueue {
- private CountDownLatch countDownLatch = new CountDownLatch(1);
+ private final Semaphore semaphore;
+ private final List