线程之间的协作(等待超时模式)
等待超时模式:
假设等待时间为 T ,在当前时间NOW + T 之后就会超时
等待超时模式伪代码:
/** * 等待的时间 */ long remain = T; /** * 超时时间 */ long overtime = now + T; while (result 不满足条件 && remain > 0){ // 进入等待 wait(remain); // 时间重新赋值 计算剩余等待时间 remain = overtime - now; } result result;
使用等待超时模式实现一个简单的数据库连接池
package org.dance.day1.pool; import org.dance.tools.SleepTools; import java.sql.*; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; /** * 数据库连接 * @author ZYGisComputer */ public class SqlConnection implements Connection { /** * 获取数据库连接 * @return */ public static final Connection fetchConnection(){ return new SqlConnection(); } @Override public void commit() throws SQLException { SleepTools.ms(70); } @Override public Statement createStatement() throws SQLException { SleepTools.ms(1); return null; } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return null; } @Override public CallableStatement prepareCall(String sql) throws SQLException { return null; } @Override public String nativeSQL(String sql) throws SQLException { return null; } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { } @Override public boolean getAutoCommit() throws SQLException { return false; } @Override public void rollback() throws SQLException { } @Override public void close() throws SQLException { } @Override public boolean isClosed() throws SQLException { return false; } @Override public DatabaseMetaData getMetaData() throws SQLException { return null; } @Override public void setReadOnly(boolean readOnly) throws SQLException { } @Override public boolean isReadOnly() throws SQLException { return false; } @Override public void setCatalog(String catalog) throws SQLException { } @Override public String getCatalog() throws SQLException { return null; } @Override public void setTransactionIsolation(int level) throws SQLException { } @Override public int getTransactionIsolation() throws SQLException { return 0; } @Override public SQLWarning getWarnings() throws SQLException { return null; } @Override public void clearWarnings() throws SQLException { } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return null; } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { return null; } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { } @Override public void setHoldability(int holdability) throws SQLException { } @Override public int getHoldability() throws SQLException { return 0; } @Override public Savepoint setSavepoint() throws SQLException { return null; } @Override public Savepoint setSavepoint(String name) throws SQLException { return null; } @Override public void rollback(Savepoint savepoint) throws SQLException { } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return null; } @Override public Clob createClob() throws SQLException { return null; } @Override public Blob createBlob() throws SQLException { return null; } @Override public NClob createNClob() throws SQLException { return null; } @Override public SQLXML createSQLXML() throws SQLException { return null; } @Override public boolean isValid(int timeout) throws SQLException { return false; } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { } @Override public String getClientInfo(String name) throws SQLException { return null; } @Override public Properties getClientInfo() throws SQLException { return null; } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return null; } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return null; } @Override public void setSchema(String schema) throws SQLException { } @Override public String getSchema() throws SQLException { return null; } @Override public void abort(Executor executor) throws SQLException { } @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { } @Override public int getNetworkTimeout() throws SQLException { return 0; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } }
package org.dance.day1.pool; import java.sql.Connection; import java.util.LinkedList; /** * 数据库连接池 * * @author ZYGisComputer */ public class DBPool { /** * 连接池,采用LinkedList链表实现有序 */ private static final LinkedList<Connection> pool = new LinkedList<Connection>(); /** * 初始化池大小 * @param initialSize */ public DBPool(int initialSize) { if (0 < initialSize) { for (int i = 0; i < initialSize; i++) { pool.addLast(SqlConnection.fetchConnection()); } } } /** * 获取数据库连接 * @param mills 超时时间 * @return connection 连接 * @throws InterruptedException 中断异常 */ public Connection fetchConnection(long mills) throws InterruptedException { // 需要锁住数据库池 synchronized (pool){ // 判断超时时间 if(0>mills){ // 如果小于0 那么永不超时 while(pool.isEmpty()){ pool.wait(); } return pool.removeFirst(); }else{ // 获取过期时间 long overtime = System.currentTimeMillis() + mills; // 获取等待时间 long remain = mills; while (pool.isEmpty()&&remain>0){ pool.wait(remain); remain = overtime - System.currentTimeMillis(); } // 到这里的时候 要么是等待时间过期了 要么是连接池有连接了 Connection connection = null; // 再次尝试去拿一下 if(!pool.isEmpty()){ connection = pool.removeFirst(); } return connection; } } } /** * 释放数据库连接 * @param connection */ public void releaseConnection(Connection connection){ if(null!=connection){ synchronized (pool){ pool.addLast(connection); // 放回连接需要通知在线程池上等待的线程 pool.notifyAll(); } } } }
package org.dance.day1.pool; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; /** * 测试数据库连接池 * @author ZYGisComputer */ public class DBPoolTest { /** * 初始化连接池 */ static DBPool dbPool = new DBPool(10); static CountDownLatch countDownLatch; public static void main(String[] args) throws InterruptedException { // 线程数量 int threadCount = 50; countDownLatch = new CountDownLatch(threadCount); // 每个线程操作的次数 int count = 20; // 计数器:统计可以拿到链接的线程的数量 AtomicInteger get = new AtomicInteger(); // 计数器:统计没有拿到链接的线程的数量 AtomicInteger noGet = new AtomicInteger(); for (int i = 0; i < threadCount; i++) { Thread thread = new Thread(new Worker(count,get,noGet),"worker_"+i); thread.start(); } countDownLatch.await(); System.out.println("总共尝试了:"+(threadCount * count)); System.out.println("拿到链接的次数:"+get.get()); System.out.println("没有拿到链接的次数:"+noGet.get()); } static class Worker implements Runnable{ int count; AtomicInteger get; AtomicInteger noGet; public Worker(int count, AtomicInteger get, AtomicInteger noGet) { this.count = count; this.get = get; this.noGet = noGet; } @Override public void run() { while (count>0){ try { // 从数据库连接池开始拿链接,如果1秒内没有拿到链接将会返回null // 然后统计拿到和没拿到的数量 Connection connection = dbPool.fetchConnection(1000); if(null!=connection){ try { connection.createStatement(); connection.commit(); } finally { dbPool.releaseConnection(connection); get.incrementAndGet(); System.out.println(Thread.currentThread().getName()+":拿到了线程"); } }else{ noGet.incrementAndGet(); } } catch (Exception e) { e.printStackTrace(); } finally { count--; } } countDownLatch.countDown(); } } }
作者:彼岸舞
时间:2020\09\16
内容关于:并发编程
本文来源于网络,只做技术分享,一概不负任何责任