diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 69e310f117..fd96da66d0 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -686,7 +686,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat public void run() { initedLatch.countDown(); - final List evictList = new ArrayList(); for (;;) { // 从前面开始删除 try { @@ -705,54 +704,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat continue; } - lock.lock(); - try { - final int checkCount = poolingCount - minIdle; - - for (int i = 0; i < checkCount; ++i) { - ConnectionHolder connection = connections[i]; - - long idleMillis = System.currentTimeMillis() - connection.getLastActiveTimeMillis(); - if (idleMillis >= minEvictableIdleTimeMillis) { - evictList.add(connection); - } else { - break; - } - } - int removeCount = evictList.size(); - if (removeCount > 0) { - System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount); - Arrays.fill(connections, poolingCount - removeCount, poolingCount, null); - poolingCount -= removeCount; - } - } finally { - lock.unlock(); - } - - for (ConnectionHolder item : evictList) { - Connection connection = item.getConnection(); - JdbcUtils.close(connection); - destroyCount++; - } - - if (evictList.size() > 0) { - if (LOG.isDebugEnabled()) { - StringBuilder buf = new StringBuilder(); - buf.append("evict "); - buf.append(evictList.size()); - buf.append(", ["); - for (int i = 0; i < evictList.size(); ++i) { - if (i != 0) { - buf.append(","); - } - buf.append(System.identityHashCode(evictList.get(i))); - } - buf.append("]"); - LOG.debug(buf.toString()); - } - } - - evictList.clear(); + shrink(true); } catch (InterruptedException e) { break; } @@ -1104,16 +1056,30 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return new CompositeDataSupport(JdbcStatManager.getDataSourceCompositeType(), map); } - + @Override public void shrink() { + shrink(false); + } + + public void shrink(boolean checkTime) { final List evictList = new ArrayList(); lock.lock(); try { final int checkCount = poolingCount - minIdle; for (int i = 0; i < checkCount; ++i) { ConnectionHolder connection = connections[i]; - evictList.add(connection); + + if (checkTime) { + long idleMillis = System.currentTimeMillis() - connection.getLastActiveTimeMillis(); + if (idleMillis >= minEvictableIdleTimeMillis) { + evictList.add(connection); + } else { + break; + } + } else { + evictList.add(connection); + } } int removeCount = evictList.size(); diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent.java b/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent.java index 39a4199efb..f318797640 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent.java @@ -48,8 +48,8 @@ public class TestIdle3_Concurrent extends TestCase { conn.close(); Assert.assertEquals(0, dataSource.getDestroyCount()); - Assert.assertEquals(2, driver.getConnections().size()); - Assert.assertEquals(2, dataSource.getCreateCount()); + Assert.assertEquals(1, driver.getConnections().size()); + Assert.assertEquals(1, dataSource.getCreateCount()); Assert.assertEquals(0, dataSource.getActiveCount()); } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_MaxActive.java b/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_MaxActive.java index 121a16a74d..acd46d0a69 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_MaxActive.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_MaxActive.java @@ -61,8 +61,9 @@ public class TestIdle3_Concurrent_MaxActive extends TestCase { for (int i = 0; i < 1000; ++i) { concurrent(200); - Assert.assertEquals("" + i, dataSource.getMaxActive(), dataSource.getPoolingCount()); + Assert.assertEquals(dataSource.getMaxActive(), dataSource.getPoolingCount()); dataSource.shrink(); + Assert.assertEquals(dataSource.getMinIdle(), dataSource.getPoolingCount()); } // 连续打开关闭单个连接 @@ -90,7 +91,7 @@ public class TestIdle3_Concurrent_MaxActive extends TestCase { try { startLatch.await(); Connection conn = dataSource.getConnection(); - long millis = new Random().nextInt(5) + 5; + long millis = new Random().nextInt(5) + 10; Thread.sleep(millis); conn.close(); } catch (Exception e) { diff --git a/src/test/java/com/alibaba/druid/pool/TestIdle3_Concurrent_MaxActive.java b/src/test/java/com/alibaba/druid/pool/TestIdle3_Concurrent_MaxActive.java new file mode 100644 index 0000000000..bad16fb404 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/TestIdle3_Concurrent_MaxActive.java @@ -0,0 +1,115 @@ +package com.alibaba.druid.pool; + +import java.lang.management.ManagementFactory; +import java.sql.Connection; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +import javax.management.ObjectName; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.mock.MockDriver; +import com.alibaba.druid.pool.DruidDataSource; + +public class TestIdle3_Concurrent_MaxActive extends TestCase { + + private MockDriver driver; + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + driver = new MockDriver(); + + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setDriver(driver); + dataSource.setInitialSize(1); + dataSource.setMaxActive(14); + dataSource.setMaxIdle(14); + dataSource.setMinIdle(1); + dataSource.setMinEvictableIdleTimeMillis(300 * 1000); // 300 / 10 + dataSource.setTimeBetweenEvictionRunsMillis(180 * 1000); // 180 / 10 + dataSource.setTestWhileIdle(true); + dataSource.setTestOnBorrow(false); + dataSource.setValidationQuery("SELECT 1"); + dataSource.setFilters("stat"); + } + + public void test_idle2() throws Exception { + +// ManagementFactory.getPlatformMBeanServer().registerMBean(dataSource, +// new ObjectName("com.alibaba:type=DataSource")); + + // 第一次创建连接 + { + Assert.assertEquals(0, dataSource.getCreateCount()); + Assert.assertEquals(0, dataSource.getActiveCount()); + + Connection conn = dataSource.getConnection(); + + Assert.assertEquals(dataSource.getInitialSize(), dataSource.getCreateCount()); + Assert.assertEquals(dataSource.getInitialSize(), driver.getConnections().size()); + Assert.assertEquals(1, dataSource.getActiveCount()); + + conn.close(); + Assert.assertEquals(0, dataSource.getDestroyCount()); + Assert.assertEquals(1, driver.getConnections().size()); + Assert.assertEquals(1, dataSource.getCreateCount()); + Assert.assertEquals(0, dataSource.getActiveCount()); + } + + for (int i = 0; i < 1000; ++i) { + concurrent(200); + Assert.assertEquals("" + i, true, dataSource.getPoolingCount() <= dataSource.getMaxActive()); + dataSource.shrink(); + } + + // 连续打开关闭单个连接 + for (int i = 0; i < 1000; ++i) { + Assert.assertEquals(0, dataSource.getActiveCount()); + Connection conn = dataSource.getConnection(); + + Assert.assertEquals(1, dataSource.getActiveCount()); + conn.close(); + } + // Assert.assertEquals(2, dataSource.getPoolingCount()); + + dataSource.close(); + } + + private void concurrent(final int threadCount) throws Exception { + Thread[] threads = new Thread[threadCount]; + final CountDownLatch startLatch = new CountDownLatch(1); + final CountDownLatch endLatch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + threads[i] = new Thread("thread-" + i) { + + public void run() { + try { + startLatch.await(); + for (int i = 0; i < 1000; ++i) { + Connection conn = dataSource.getConnection(); + conn.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + endLatch.countDown(); + } + } + }; + } + + startLatch.countDown(); + for (int i = 0; i < threadCount; ++i) { + threads[i].start(); + } + + endLatch.await(); + + // int max = count > dataSource.getMaxActive() ? dataSource.getMaxActive() : count; + // Assert.assertEquals(max, driver.getConnections().size()); + } +}