什么是JUC?

  JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些东西

  该包的位置位于java下面的rt.jar包下面

4大常用并发工具类:

  CountDownLatch

  CyclicBarrier

  Semaphore

  ExChanger

CountDownLatch:

  CountDownLatch,俗称闭锁,作用是类似加强版的Join,是让一组线程等待其他的线程完成工作以后才执行

  就比如在启动框架服务的时候,我们主线程需要在环境线程初始化完成之后才能启动,这时候我们就可以实现使用CountDownLatch来完成

  1. /**
  2. * Constructs a {@code CountDownLatch} initialized with the given count.
  3. *
  4. * @param count the number of times {@link #countDown} must be invoked
  5. * before threads can pass through {@link #await}
  6. * @throws IllegalArgumentException if {@code count} is negative
  7. */
  8. public CountDownLatch(int count) {
  9. if (count < 0) throw new IllegalArgumentException("count < 0");
  10. this.sync = new Sync(count);
  11. }

  在源码中可以看到,创建CountDownLatch时,需要传入一个int类型的参数,将决定在执行次扣减之后,等待的线程被唤醒

   通过这个类图就可以知道其实CountDownLatch并没有多少东西

  方法介绍:

    CountDownLatch:初始化方法

    await:等待方法,同时带参数的是超时重载方法

    countDown:每执行一次,计数器减一,就是初始化传入的数字,也代表着一个线程完成了任务

    getCount:获取当前值

    toString:这个就不用说了

  里面的Sync是一个内部类,外面的方法其实都是操作这个内部类的,这个内部类继承了AQS,实现的标准方法,AQS将在后面的章节写

主线程中创建CountDownLatch(3),然后主线程await阻塞,然后线程A,B,C各自完成了任务,调用了countDown,之后,每个线程调用一次计数器就会减一,初始是3,然后A线程调用后变成2,B线程调用后变成1,C线程调用后,变成0,这时就会唤醒正在await的主线程,然后主线程继续执行

说一千道一万,不如代码写几行,上代码:

休眠工具类,之后的代码都会用到

  1. package org.dance.tools;
  2.  
  3. import java.util.concurrent.TimeUnit;
  4.  
  5. /**
  6. * 类说明:线程休眠辅助工具类
  7. */
  8. public class SleepTools {
  9.  
  10. /**
  11. * 按秒休眠
  12. * @param seconds 秒数
  13. */
  14. public static final void second(int seconds) {
  15. try {
  16. TimeUnit.SECONDS.sleep(seconds);
  17. } catch (InterruptedException e) {
  18. }
  19. }
  20.  
  21. /**
  22. * 按毫秒数休眠
  23. * @param seconds 毫秒数
  24. */
  25. public static final void ms(int seconds) {
  26. try {
  27. TimeUnit.MILLISECONDS.sleep(seconds);
  28. } catch (InterruptedException e) {
  29. }
  30. }
  31. }
  1. package org.dance.day2.util;
  2.  
  3. import org.dance.tools.SleepTools;
  4.  
  5. import java.util.concurrent.CountDownLatch;
  6.  
  7. /**
  8. * CountDownLatch的使用,有五个线程,6个扣除点
  9. * 扣除完成后主线程和业务线程,才能执行工作
  10. * 扣除点一般都是大于等于需要初始化的线程的
  11. * @author ZYGisComputer
  12. */
  13. public class UseCountDownLatch {
  14.  
  15. /**
  16. * 设置为6个扣除点
  17. */
  18. static CountDownLatch countDownLatch = new CountDownLatch(6);
  19.  
  20. /**
  21. * 初始化线程
  22. */
  23. private static class InitThread implements Runnable {
  24.  
  25. @Override
  26. public void run() {
  27.  
  28. System.out.println("thread_" + Thread.currentThread().getId() + " ready init work .....");
  29.  
  30. // 执行扣减 扣减不代表结束
  31. countDownLatch.countDown();
  32.  
  33. for (int i = 0; i < 2; i++) {
  34. System.out.println("thread_" + Thread.currentThread().getId() + ".....continue do its work");
  35. }
  36.  
  37. }
  38. }
  39.  
  40. /**
  41. * 业务线程
  42. */
  43. private static class BusiThread implements Runnable {
  44.  
  45. @Override
  46. public void run() {
  47.  
  48. // 业务线程需要在等初始化完毕后才能执行
  49. try {
  50. countDownLatch.await();
  51. for (int i = 0; i < 3; i++) {
  52. System.out.println("BusiThread " + Thread.currentThread().getId() + " do business-----");
  53. }
  54. } catch (InterruptedException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. }
  59.  
  60. public static void main(String[] args) {
  61.  
  62. // 创建单独的初始化线程
  63. new Thread(){
  64. @Override
  65. public void run() {
  66. SleepTools.ms(1);
  67. System.out.println("thread_" + Thread.currentThread().getId() + " ready init work step 1st.....");
  68. // 扣减一次
  69. countDownLatch.countDown();
  70. System.out.println("begin stop 2nd.....");
  71. SleepTools.ms(1);
  72. System.out.println("thread_" + Thread.currentThread().getId() + " ready init work step 2nd.....");
  73. // 扣减一次
  74. countDownLatch.countDown();
  75.  
  76. }
  77. }.start();
  78. // 启动业务线程
  79. new Thread(new BusiThread()).start();
  80. // 启动初始化线程
  81. for (int i = 0; i <= 3; i++) {
  82. new Thread(new InitThread()).start();
  83. }
  84. // 主线程进入等待
  85. try {
  86. countDownLatch.await();
  87. System.out.println("Main do ites work.....");
  88. } catch (InterruptedException e) {
  89. e.printStackTrace();
  90. }
  91.  
  92. }
  93.  
  94. }

返回结果:

  1. thread_13 ready init work .....
  2. thread_13.....continue do its work
  3. thread_13.....continue do its work
  4. thread_14 ready init work .....
  5. thread_14.....continue do its work
  6. thread_14.....continue do its work
  7. thread_15 ready init work .....
  8. thread_15.....continue do its work
  9. thread_11 ready init work step 1st.....
  10. begin stop 2nd.....
  11. thread_16 ready init work .....
  12. thread_16.....continue do its work
  13. thread_16.....continue do its work
  14. thread_15.....continue do its work
  15. thread_11 ready init work step 2nd.....
  16. Main do ites work.....
  17. BusiThread 12 do business-----
  18. BusiThread 12 do business-----
  19. BusiThread 12 do business-----

通过返回结果就可以很直接的看到业务线程是在初始化线程完全跑完之后,才开始执行的

CyclicBarrier:

  CyclicBarrier,俗称栅栏锁,作用是让一组线程到达某个屏障,被阻塞,一直到组内的最后一个线程到达,然后屏障开放,接着,所有的线程继续运行

  这个感觉和CountDownLatch有点相似,但是其实是不一样的,所谓的差别,将在下面详解

  CyclicBarrier的构造参数有两个

  1. /**
  2. * Creates a new {@code CyclicBarrier} that will trip when the
  3. * given number of parties (threads) are waiting upon it, and
  4. * does not perform a predefined action when the barrier is tripped.
  5. *
  6. * @param parties the number of threads that must invoke {@link #await}
  7. * before the barrier is tripped
  8. * @throws IllegalArgumentException if {@code parties} is less than 1
  9. */
  10. public CyclicBarrier(int parties) {
  11. this(parties, null);
  12. }
  1. /**
  2. * Creates a new {@code CyclicBarrier} that will trip when the
  3. * given number of parties (threads) are waiting upon it, and which
  4. * will execute the given barrier action when the barrier is tripped,
  5. * performed by the last thread entering the barrier.
  6. *
  7. * @param parties the number of threads that must invoke {@link #await}
  8. * before the barrier is tripped
  9. * @param barrierAction the command to execute when the barrier is
  10. * tripped, or {@code null} if there is no action
  11. * @throws IllegalArgumentException if {@code parties} is less than 1
  12. */
  13. public CyclicBarrier(int parties, Runnable barrierAction) {
  14. if (parties <= 0) throw new IllegalArgumentException();
  15. this.parties = parties;
  16. this.count = parties;
  17. this.barrierCommand = barrierAction;
  18. }

很明显能感觉出来,上面的构造参数调用了下面的构造参数,是一个构造方法重载

首先这个第一个参数也树Int类型的,传入的是执行线程的个数,这个数量和CountDownLatch不一样,这个数量是需要和线程数量吻合的,CountDownLatch则不一样,CountDownLatch可以大于等于,而CyclicBarrier只能等于,然后是第二个参数,第二个参数是barrierAction,这个参数是当屏障开放后,执行的任务线程,如果当屏障开放后需要执行什么任务,可以写在这个线程中

主线程创建CyclicBarrier(3,barrierAction),然后由线程开始执行,线程A,B执行完成后都调用了await,然后他们都在一个屏障前阻塞者,需要等待线程C也,执行完成,调用await之后,然后三个线程都达到屏障后,屏障开放,然后线程继续执行,并且barrierAction在屏障开放的一瞬间也开始执行

上代码:

  1. package org.dance.day2.util;
  2.  
  3. import org.dance.tools.SleepTools;
  4.  
  5. import java.util.Map;
  6. import java.util.Random;
  7. import java.util.concurrent.BrokenBarrierException;
  8. import java.util.concurrent.ConcurrentHashMap;
  9. import java.util.concurrent.CyclicBarrier;
  10.  
  11. /**
  12. * CyclicBarrier的使用
  13. *
  14. * @author ZYGisComputer
  15. */
  16. public class UseCyclicBarrier {
  17.  
  18. /**
  19. * 存放子线程工作结果的安全容器
  20. */
  21. private static ConcurrentHashMap<String, Long> resultMap = new ConcurrentHashMap<>();
  22.  
  23. private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new CollectThread());
  24.  
  25. /**
  26. * 结果打印线程
  27. * 用来演示CyclicBarrier的第二个参数,barrierAction
  28. */
  29. private static class CollectThread implements Runnable {
  30.  
  31. @Override
  32. public void run() {
  33.  
  34. StringBuffer result = new StringBuffer();
  35.  
  36. for (Map.Entry<String, Long> workResult : resultMap.entrySet()) {
  37. result.append("[" + workResult.getValue() + "]");
  38. }
  39.  
  40. System.out.println("the result = " + result);
  41. System.out.println("do other business.....");
  42.  
  43. }
  44. }
  45.  
  46. /**
  47. * 工作子线程
  48. * 用于CyclicBarrier的一组线程
  49. */
  50. private static class SubThread implements Runnable {
  51.  
  52. @Override
  53. public void run() {
  54.  
  55. // 获取当前线程的ID
  56. long id = Thread.currentThread().getId();
  57.  
  58. // 放入统计容器中
  59. resultMap.put(String.valueOf(id), id);
  60.  
  61. Random random = new Random();
  62.  
  63. try {
  64. if (random.nextBoolean()) {
  65. Thread.sleep(1000 + id);
  66. System.out.println("Thread_"+id+"..... do something");
  67. }
  68. System.out.println(id+" is await");
  69. cyclicBarrier.await();
  70. Thread.sleep(1000+id);
  71. System.out.println("Thread_"+id+".....do its business");
  72. } catch (InterruptedException e) {
  73. e.printStackTrace();
  74. } catch (BrokenBarrierException e) {
  75. e.printStackTrace();
  76. }
  77.  
  78. }
  79. }
  80.  
  81. public static void main(String[] args) {
  82.  
  83. for (int i = 0; i <= 4; i++) {
  84. Thread thread = new Thread(new SubThread());
  85. thread.start();
  86. }
  87.  
  88. }
  89.  
  90. }

返回结果:

  1. 11 is await
  2. 14 is await
  3. 15 is await
  4. Thread_12..... do something
  5. 12 is await
  6. Thread_13..... do something
  7. 13 is await
  8. the result = [11][12][13][14][15]
  9. do other business.....
  10. Thread_11.....do its business
  11. Thread_12.....do its business
  12. Thread_13.....do its business
  13. Thread_14.....do its business
  14. Thread_15.....do its business

通过返回结果可以看出前面的11 14 15三个线程没有进入if语句块,在执行到await的时候进入了等待,而另外12 13两个线程进入到了if语句块当中,多休眠了1秒多,然后当5个线程同时到达await的时候,屏障开放,执行了barrierAction线程,然后线程组继续执行

解释一下CountDownLatch和CyclicBarrier的却别吧!

首先就是CountDownLatch的构造参数传入的数量一般都是大于等于线程,数量的,因为他是有第三方控制的,可以扣减多次,然后就是CyclicBarrier的构造参数第一个参数传入的数量一定是等于线程的个数的,因为他是由一组线程自身控制的

区别

      CountDownLatch  CyclicBarrier

控制         第三方控制       自身控制

传入数量  大于等于线程数量       等于线程数量

Semaphore:

  Semaphore,俗称信号量,作用于控制同时访问某个特定资源的线程数量,用在流量控制

  一说特定资源控制,那么第一时间就想到了数据库连接..

  之前用等待超时模式写了一个数据库连接池,打算用这个Semaphone也写一个

  1. /**
  2. * Creates a {@code Semaphore} with the given number of
  3. * permits and nonfair fairness setting.
  4. *
  5. * @param permits the initial number of permits available.
  6. * This value may be negative, in which case releases
  7. * must occur before any acquires will be granted.
  8. */
  9. public Semaphore(int permits) {
  10. sync = new NonfairSync(permits);
  11. }

在源码中可以看到在构建Semaphore信号量的时候,需要传入许可证的数量,这个数量就是资源的最大允许的访问的线程数

接下里用信号量实现一个数据库连接池

连接对象

  1. package org.dance.day2.util.pool;
  2.  
  3. import org.dance.tools.SleepTools;
  4.  
  5. import java.sql.*;
  6. import java.util.Map;
  7. import java.util.Properties;
  8. import java.util.concurrent.Executor;
  9.  
  10. /**
  11. * 数据库连接
  12. * @author ZYGisComputer
  13. */
  14. public class SqlConnection implements Connection {
  15.  
  16. /**
  17. * 获取数据库连接
  18. * @return
  19. */
  20. public static final Connection fetchConnection(){
  21. return new SqlConnection();
  22. }
  23.  
  24. @Override
  25. public void commit() throws SQLException {
  26. SleepTools.ms(70);
  27. }
  28.  
  29. @Override
  30. public Statement createStatement() throws SQLException {
  31. SleepTools.ms(1);
  32. return null;
  33. }
  34.  
  35. @Override
  36. public PreparedStatement prepareStatement(String sql) throws SQLException {
  37. return null;
  38. }
  39.  
  40. @Override
  41. public CallableStatement prepareCall(String sql) throws SQLException {
  42. return null;
  43. }
  44.  
  45. @Override
  46. public String nativeSQL(String sql) throws SQLException {
  47. return null;
  48. }
  49.  
  50. @Override
  51. public void setAutoCommit(boolean autoCommit) throws SQLException {
  52.  
  53. }
  54.  
  55. @Override
  56. public boolean getAutoCommit() throws SQLException {
  57. return false;
  58. }
  59.  
  60. @Override
  61. public void rollback() throws SQLException {
  62.  
  63. }
  64.  
  65. @Override
  66. public void close() throws SQLException {
  67.  
  68. }
  69.  
  70. @Override
  71. public boolean isClosed() throws SQLException {
  72. return false;
  73. }
  74.  
  75. @Override
  76. public DatabaseMetaData getMetaData() throws SQLException {
  77. return null;
  78. }
  79.  
  80. @Override
  81. public void setReadOnly(boolean readOnly) throws SQLException {
  82.  
  83. }
  84.  
  85. @Override
  86. public boolean isReadOnly() throws SQLException {
  87. return false;
  88. }
  89.  
  90. @Override
  91. public void setCatalog(String catalog) throws SQLException {
  92.  
  93. }
  94.  
  95. @Override
  96. public String getCatalog() throws SQLException {
  97. return null;
  98. }
  99.  
  100. @Override
  101. public void setTransactionIsolation(int level) throws SQLException {
  102.  
  103. }
  104.  
  105. @Override
  106. public int getTransactionIsolation() throws SQLException {
  107. return 0;
  108. }
  109.  
  110. @Override
  111. public SQLWarning getWarnings() throws SQLException {
  112. return null;
  113. }
  114.  
  115. @Override
  116. public void clearWarnings() throws SQLException {
  117.  
  118. }
  119.  
  120. @Override
  121. public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
  122. return null;
  123. }
  124.  
  125. @Override
  126. public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  127. return null;
  128. }
  129.  
  130. @Override
  131. public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  132. return null;
  133. }
  134.  
  135. @Override
  136. public Map<String, Class<?>> getTypeMap() throws SQLException {
  137. return null;
  138. }
  139.  
  140. @Override
  141. public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
  142.  
  143. }
  144.  
  145. @Override
  146. public void setHoldability(int holdability) throws SQLException {
  147.  
  148. }
  149.  
  150. @Override
  151. public int getHoldability() throws SQLException {
  152. return 0;
  153. }
  154.  
  155. @Override
  156. public Savepoint setSavepoint() throws SQLException {
  157. return null;
  158. }
  159.  
  160. @Override
  161. public Savepoint setSavepoint(String name) throws SQLException {
  162. return null;
  163. }
  164.  
  165. @Override
  166. public void rollback(Savepoint savepoint) throws SQLException {
  167.  
  168. }
  169.  
  170. @Override
  171. public void releaseSavepoint(Savepoint savepoint) throws SQLException {
  172.  
  173. }
  174.  
  175. @Override
  176. public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  177. return null;
  178. }
  179.  
  180. @Override
  181. public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  182. return null;
  183. }
  184.  
  185. @Override
  186. public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  187. return null;
  188. }
  189.  
  190. @Override
  191. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
  192. return null;
  193. }
  194.  
  195. @Override
  196. public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
  197. return null;
  198. }
  199.  
  200. @Override
  201. public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
  202. return null;
  203. }
  204.  
  205. @Override
  206. public Clob createClob() throws SQLException {
  207. return null;
  208. }
  209.  
  210. @Override
  211. public Blob createBlob() throws SQLException {
  212. return null;
  213. }
  214.  
  215. @Override
  216. public NClob createNClob() throws SQLException {
  217. return null;
  218. }
  219.  
  220. @Override
  221. public SQLXML createSQLXML() throws SQLException {
  222. return null;
  223. }
  224.  
  225. @Override
  226. public boolean isValid(int timeout) throws SQLException {
  227. return false;
  228. }
  229.  
  230. @Override
  231. public void setClientInfo(String name, String value) throws SQLClientInfoException {
  232.  
  233. }
  234.  
  235. @Override
  236. public void setClientInfo(Properties properties) throws SQLClientInfoException {
  237.  
  238. }
  239.  
  240. @Override
  241. public String getClientInfo(String name) throws SQLException {
  242. return null;
  243. }
  244.  
  245. @Override
  246. public Properties getClientInfo() throws SQLException {
  247. return null;
  248. }
  249.  
  250. @Override
  251. public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
  252. return null;
  253. }
  254.  
  255. @Override
  256. public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
  257. return null;
  258. }
  259.  
  260. @Override
  261. public void setSchema(String schema) throws SQLException {
  262.  
  263. }
  264.  
  265. @Override
  266. public String getSchema() throws SQLException {
  267. return null;
  268. }
  269.  
  270. @Override
  271. public void abort(Executor executor) throws SQLException {
  272.  
  273. }
  274.  
  275. @Override
  276. public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
  277.  
  278. }
  279.  
  280. @Override
  281. public int getNetworkTimeout() throws SQLException {
  282. return 0;
  283. }
  284.  
  285. @Override
  286. public <T> T unwrap(Class<T> iface) throws SQLException {
  287. return null;
  288. }
  289.  
  290. @Override
  291. public boolean isWrapperFor(Class<?> iface) throws SQLException {
  292. return false;
  293. }
  294. }

连接池对象

  1. package org.dance.day2.util.pool;
  2.  
  3. import java.sql.Connection;
  4. import java.util.ArrayList;
  5. import java.util.HashSet;
  6. import java.util.Iterator;
  7. import java.util.LinkedList;
  8. import java.util.concurrent.Semaphore;
  9.  
  10. /**
  11. * 使用信号量控制数据库的链接和释放
  12. *
  13. * @author ZYGisComputer
  14. */
  15. public class DBPoolSemaphore {
  16.  
  17. /**
  18. * 池容量
  19. */
  20. private final static int POOL_SIZE = 10;
  21.  
  22. /**
  23. * useful 代表可用连接
  24. * useless 代表已用连接
  25. * 为什么要使用两个Semaphore呢?是因为,在连接池中不只有连接本身是资源,空位也是资源,也需要记录
  26. */
  27. private final Semaphore useful, useless;
  28.  
  29. /**
  30. * 连接池
  31. */
  32. private final static LinkedList<Connection> POOL = new LinkedList<>();
  33.  
  34. /**
  35. * 使用静态块初始化池
  36. */
  37. static {
  38. for (int i = 0; i < POOL_SIZE; i++) {
  39. POOL.addLast(SqlConnection.fetchConnection());
  40. }
  41. }
  42.  
  43. public DBPoolSemaphore() {
  44. // 初始可用的许可证等于池容量
  45. useful = new Semaphore(POOL_SIZE);
  46. // 初始不可用的许可证容量为0
  47. useless = new Semaphore(0);
  48. }
  49.  
  50. /**
  51. * 获取数据库连接
  52. *
  53. * @return 连接对象
  54. */
  55. public Connection takeConnection() throws InterruptedException {
  56. // 可用许可证减一
  57. useful.acquire();
  58. Connection connection;
  59. synchronized (POOL) {
  60. connection = POOL.removeFirst();
  61. }
  62. // 不可用许可证数量加一
  63. useless.release();
  64. return connection;
  65. }
  66.  
  67. /**
  68. * 释放链接
  69. *
  70. * @param connection 连接对象
  71. */
  72. public void returnConnection(Connection connection) throws InterruptedException {
  73. if(null!=connection){
  74. // 打印日志
  75. System.out.println("当前有"+useful.getQueueLength()+"个线程等待获取连接,,"
  76. +"可用连接有"+useful.availablePermits()+"个");
  77. // 不可用许可证减一
  78. useless.acquire();
  79. synchronized (POOL){
  80. POOL.addLast(connection);
  81. }
  82. // 可用许可证加一
  83. useful.release();
  84. }
  85. }
  86.  
  87. }

测试类:

  1. package org.dance.day2.util.pool;
  2.  
  3. import org.dance.tools.SleepTools;
  4.  
  5. import java.sql.Connection;
  6. import java.util.Random;
  7.  
  8. /**
  9. * 测试Semaphore
  10. * @author ZYGisComputer
  11. */
  12. public class UseSemaphore {
  13.  
  14. /**
  15. * 连接池
  16. */
  17. public static final DBPoolSemaphore pool = new DBPoolSemaphore();
  18.  
  19. private static class BusiThread extends Thread{
  20. @Override
  21. public void run() {
  22. // 随机数工具类 为了让每个线程持有连接的时间不一样
  23. Random random = new Random();
  24. long start = System.currentTimeMillis();
  25. try {
  26. Connection connection = pool.takeConnection();
  27. System.out.println("Thread_"+Thread.currentThread().getId()+
  28. "_获取数据库连接耗时["+(System.currentTimeMillis()-start)+"]ms.");
  29. // 模拟使用连接查询数据
  30. SleepTools.ms(100+random.nextInt(100));
  31. System.out.println("查询数据完成归还连接");
  32. pool.returnConnection(connection);
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38.  
  39. public static void main(String[] args) {
  40. for (int i = 0; i < 50; i++) {
  41. BusiThread busiThread = new BusiThread();
  42. busiThread.start();
  43. }
  44. }
  45.  
  46. }

测试返回结果:

  1. Thread_11_获取数据库连接耗时[0]ms.
  2. Thread_12_获取数据库连接耗时[0]ms.
  3. Thread_13_获取数据库连接耗时[0]ms.
  4. Thread_14_获取数据库连接耗时[0]ms.
  5. Thread_15_获取数据库连接耗时[0]ms.
  6. Thread_16_获取数据库连接耗时[0]ms.
  7. Thread_17_获取数据库连接耗时[0]ms.
  8. Thread_18_获取数据库连接耗时[0]ms.
  9. Thread_19_获取数据库连接耗时[0]ms.
  10. Thread_20_获取数据库连接耗时[0]ms.
  11. 查询数据完成归还连接
  12. 当前有40个线程等待获取连接,,可用连接有0
  13. Thread_21_获取数据库连接耗时[112]ms.
  14. 查询数据完成归还连接
  15. ...................
    查询数据完成归还连接
  16. 当前有2个线程等待获取连接,,可用连接有0
  17. Thread_59_获取数据库连接耗时[637]ms.
  18. 查询数据完成归还连接
  19. 当前有1个线程等待获取连接,,可用连接有0
  20. Thread_60_获取数据库连接耗时[660]ms.
  21. 查询数据完成归还连接
  22. 当前有0个线程等待获取连接,,可用连接有0
  23. 查询数据完成归还连接
    ...................
  24. 当前有0个线程等待获取连接,,可用连接有8
  25. 查询数据完成归还连接
  26. 当前有0个线程等待获取连接,,可用连接有9

通过执行结果可以很明确的看到,一上来就有10个线程获取到了连接,,然后后面的40个线程进入阻塞,然后只有释放链接之后,等待的线程就会有一个拿到,然后越后面的线程等待的时间就越长,然后一直到所有的线程执行完毕

最后打印的可用连接有九个不是因为少了一个是因为在释放之前打印的,不是错误

从结果中可以看到,我们对连接池中的资源的到了控制,这就是信号量的流量控制

Exchanger:

  Exchanger,俗称交换器,用于在线程之间交换数据,但是比较受限,因为只能两个线程之间交换数据

  1. /**
  2. * Creates a new Exchanger.
  3. */
  4. public Exchanger() {
  5. participant = new Participant();
  6. }

这个构造函数没有什么好说的,也没有入参,只有在创建的时候指定一下需要交换的数据的泛型即可,下面看代码

  1. package org.dance.day2.util;
  2.  
  3. import java.util.HashSet;
  4. import java.util.Set;
  5. import java.util.concurrent.Exchanger;
  6.  
  7. /**
  8. * 线程之间交换数据
  9. * @author ZYGisComputer
  10. */
  11. public class UseExchange {
  12.  
  13. private static final Exchanger<Set<String>> exchanger = new Exchanger<>();
  14.  
  15. public static void main(String[] args) {
  16.  
  17. new Thread(){
  18. @Override
  19. public void run() {
  20. Set<String> aSet = new HashSet<>();
  21. aSet.add("A");
  22. aSet.add("B");
  23. aSet.add("C");
  24. try {
  25. Set<String> exchange = exchanger.exchange(aSet);
  26. for (String s : exchange) {
  27. System.out.println("aSet"+s);
  28. }
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }.start();
  34.  
  35. new Thread(){
  36. @Override
  37. public void run() {
  38. Set<String> bSet = new HashSet<>();
  39. bSet.add("1");
  40. bSet.add("2");
  41. bSet.add("3");
  42. try {
  43. Set<String> exchange = exchanger.exchange(bSet);
  44. for (String s : exchange) {
  45. System.out.println("bSet"+s);
  46. }
  47. } catch (InterruptedException e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. }.start();
  52.  
  53. }
  54.  
  55. }

执行结果:

  1. bSetA
  2. bSetB
  3. bSetC
  4. aSet1
  5. aSet2
  6. aSet3

通过执行结果可以清晰的看到,两个线程中的数据发生了交换,这就是Exchanger的线程数据交换了

以上就是JUC的4大常用并发工具类了

作者:彼岸舞

时间:2020\09\26

内容关于:并发编程

本文来源于网络,只做技术分享,一概不负任何责任

JUC 常用4大并发工具类的更多相关文章

  1. Java并发多线程 - 并发工具类JUC

    安全共享对象策略 1.线程限制 : 一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改 2.共享只读 : 一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问, 但是任何线程都 ...

  2. JUC学习笔记--JUC中并发工具类

    JUC中并发工具类 CountDownLatch CountDownLatch是我目前使用比较多的类,CountDownLatch初始化时会给定一个计数,然后每次调用countDown() 计数减1, ...

  3. Java并发编程-并发工具类及线程池

    JUC中提供了几个比较常用的并发工具类,比如CountDownLatch.CyclicBarrier.Semaphore. CountDownLatch: countdownlatch是一个同步工具类 ...

  4. 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier

    目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...

  5. 基于AQS实现的Java并发工具类

    本文主要介绍一下基于AQS实现的Java并发工具类的作用,然后简单谈一下该工具类的实现原理.其实都是AQS的相关知识,只不过在AQS上包装了一下而已.本文也是基于您在有AQS的相关知识基础上,进行讲解 ...

  6. JUC源码分析-其它工具类(一)ThreadLocalRandom

    JUC源码分析-其它工具类(一)ThreadLocalRandom ThreadLocalRandom 是 JDK7 在 JUC 包下新增的随机数生成器,它解决了 Random 在多线程下多个线程竞争 ...

  7. 【Java并发工具类】Java并发容器

    前言 Java并发包有很大一部分都是关于并发容器的.Java在5.0版本之前线程安全的容器称之为同步容器.同步容器实现线程安全的方式:是将每个公有方法都使用synchronized修饰,保证每次只有一 ...

  8. 《Java并发编程的艺术》第6/7/8章 Java并发容器与框架/13个原子操作/并发工具类

    第6章 Java并发容器和框架 6.1  ConcurrentHashMap(线程安全的HashMap.锁分段技术) 6.1.1 为什么要使用ConcurrentHashMap 在并发编程中使用Has ...

  9. Java线程的并发工具类

    Java线程的并发工具类. 一.fork/join 1. Fork-Join原理 在必要的情况下,将一个大任务,拆分(fork)成若干个小任务,然后再将一个个小任务的结果进行汇总(join). 适用场 ...

随机推荐

  1. 系综的实现方式(nve、nvt、npt)

    一.NVE系综 更新位置和速度,v和e恒定. 二.NVT系综 几种实现的方式: 如: fix 1 all nve #更新位置和速度,e和V保持不变.若只有这个命令,就只nve系综,如果和控温命令一起, ...

  2. python分支结构

    if分支 一.单分支结构 # if 表达式:#     语句块# 后续语句 # 执行流程:如果表达式结果为真,则执行语句块.否则,直接执行后续语句 二.双分支结构 # 双分支语句# if 表达式:# ...

  3. 前端系列-CS与BS的区别

    现在的系统架构有B/S与C/S之分. C/S,即Client/Server(客户端/服务器).我们一般使用的软件架构都是C/S架构,比如各个系统版本中的软件如qq管家.腾讯qq.office等.C/S ...

  4. lynx浏览器使用教程

    http://www.wocaoseo.com/thread-216-1-1.html LYNX浏览器是谷歌官方推荐的一款文本浏览器,主要用来模拟蜘蛛看到您页面时候的样子,谷歌在网站站长指南中提到: ...

  5. SEO工程师考试题目

    http://www.wocaoseo.com/thread-201-1-1.html      SEO,全名Search Engine Optimization,其中文名字为'搜索引擎优化' .其英 ...

  6. SICP之1.3中文翻译题目错误

    原版题目: Exercise 1.3: Define a procedure that takes three numbers as arguments and returns the sum of ...

  7. 力扣Leetcode 198. 打家劫舍

    打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定 ...

  8. Android开发之开源框架OKHTTP的Get请求代码,得到json字符串方法

      <span style="white-space:pre"> </span><pre name="code" class=&q ...

  9. 1090 Highest Price in Supply Chain (25 分)(模拟建树,找树的深度)牛客网过,pat没过

    A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone invo ...

  10. html打印后不刷新当前页

    这种方法可以在打印的页面中添加样式,新页面跳转打印 doPrint(ids){ var titleHTML=document.getElementById(ids).innerHTML; var Op ...