As we all know, Java Object objects provide interfaces such as wait() and notify()/notifyAll(), which are important parts of concurrent programming. They play a very important role in the cooperation between multi threads, and there are many scenarios that can be used in the actual development. Needless to say, today we will use this mechanism to simulate the implementation of a jdbc connection pool that supports the wait timeout mode.
1, Simulate and implement a database connection interface
//Class description: empty implementation of a Connection interface (because the focus is not here, the methods in the following interface only do simple processing) public class SqlConnectImpl implements Connection{ /*Take a database connection*/ public static final Connection fetchConnection(){ return new SqlConnectImpl(); } @Override public boolean isWrapperFor(Class<?> arg0) throws SQLException { // TODO Auto-generated method stub return false; } //Because the point is not here, other interfaces are omitted here }
2, The core method to realize the connection pool of database waiting timeout
//Class description: implementation of connection pool DBPool { //Simulation: database connection pool LinkedList<Connection> pool = LinkedList<Connection>()(initialSize) { if(initialSize > ) { for(int i = 0;i < initialSize; i++) { pool.addLast(SqlConnectImpl.fetchConnection()); } } } //Connection pool: release connection, notify other threads public void releaseConnection(Connection connection) { if (connection != null) { synchronized (pool){ pool.addLast(connection); pool.notifyAll(); } } } //Connection pool: get connection usage public Connection fetchConnection(long mills) throws InterruptedException { synchronized (pool){ //Timeout not set, get directly if(mills <0){ while (pool.isEmpty()){ pool.wait(); } return pool.removeFirst(); } //Set timeout long future = System.currentTimeMillis()+mills;/*Timeout*/ long remaining = mills; while (pool.isEmpty() && remaining > 0){ pool.wait(remaining); //Wake up once: recalculate the waiting time remaining = future - System.currentTimeMillis(); } Connection connection = null; if(!pool.isEmpty()){ connection = pool.removeFirst(); } return connection; } } }
3, Access to connection pool in multithreaded concurrent mode
//Class description: database connection pool test class public class DBPoolTest { static DBPool pool = new DBPool(10); //Controller: control the main thread and wait for all wokers to finish before execution static CountDownLatch end; public static void main(String[] args) throws Exception { //Number of threads int threadCount = 50; end = new CountDownLatch(threadCount); int count = 20;//Number of operations per thread AtomicInteger got = new AtomicInteger();//Counter: count the threads that can get the connection AtomicInteger notGot = new AtomicInteger();//Counter: count the threads that did not get the connection for (int i = 0; i < threadCount; i++) { Thread thread = new Thread(new Worker(count, got, notGot), "worker_"+i); thread.start(); } end.await();//main thread is waiting here System.out.println("All in all: " + (threadCount * count)); System.out.println("Number of connections received: " + got); System.out.println("Number of failed connections: " + notGot); } static class Worker implements Runnable { int count; AtomicInteger got; AtomicInteger notGot; public Worker(int count, AtomicInteger got, AtomicInteger notGot) { this.count = count; this.got = got; this.notGot = notGot; } public void run() { while (count > 0) { try { //Get the connection from the thread pool. If the connection cannot be obtained within 1000ms, null will be returned //Count the number of got connections and the number of not got connections respectively Connection connection = pool.fetchConnection(1000); if (connection != null) { try { connection.createStatement(); connection.commit(); } finally { pool.releaseConnection(connection); got.incrementAndGet(); } } else { notGot.incrementAndGet(); System.out.println(Thread.currentThread().getName() +"Wait timeout!"); } } catch (Exception ex) { } finally { count--; } } end.countDown(); } } }
4, Test result report
5, Conclusion
Conclusion: 1) it is necessary to use wait(), notify(), notifyAll() and other methods. synchronized key packages (objects, methods or blocks) can be used, and errors must be reported during package operation;
2) when the thread executes the wait() method, it will automatically release the held lock;
3) after a thread executes notify() or notifyAll(), the lock resources held by the thread will not be released immediately, and will only be released after the statement block or method of the synchronized package is executed;
4) when using notify() method to wake up, only one thread will wake up randomly, which is not applicable under the condition of multiple wakeups. It is recommended that notifyAll() be used to wake up all threads related to lock objects;