Threads cooperate with each other: The wait timeout pattern implements a connection pool
-
Scenario: The connection pool needs to be configured when the SM program is called, but there is a timeout connection in the connection pool
-
If the time limit for retrieving a connection is exceeded, an exception message will be thrown
-
On the basis of wait and notification, do this; This is the one you use in Spring MyBatist
- Wait a certain amount of time after calling a method, usually a fixed amount of time, such as 5s in connection pooling
- The call completes within the waiting time and returns normally, or if it timed out, throws an exception or returns a default value
- C3P0,DBCP, etc
-
-
Handling: Manually implementing connection pooling (jDBC-based)
-
basis
- Implements Collection interface, JDBC stuff (implements some functions)
- Databases generally have a maximum number of connections, just as the OS creates threads
-
Implementation:
- A connection pool (DBPool) holds connections: it is a container
-
Details:
-
Why use Poo to call wait
- Because it waits on the container, it notifies other threads when the pool is empty or full
-
-
Run result: missing is to realize wait timeout mode, very good
-
Dbpool. Java: database connection pool
package cn.enjoyedu.ch1.pool; import java.sql.Connection; import java.util.LinkedList; */ public class DBPool {private static LinkedList<Connection> pool = new LinkedList<Connection>(); Public DBPool(int initialSize) {if (initialSize > 0) {for (int I = 0; i < initialSize; i++) { pool.addLast(SqlConnectImpl.fetchConnection()); Public void releaseConnection(Connection Connection) {if (Connection! Synchronized (pool){pool.addlast (connection); synchronized (pool){pool.addlast (connection); // Notifies other waiting threads pool.notifyall (); }}} // The connection cannot be obtained within mills(timeout duration), null will be returned, FetchConnection (Long mills) throws InterruptedException {public Connection fetchConnection(long mills) throws InterruptedException { Synchronized (pool){if(mills<0){// Synchronize (pool); } return pool.removeFirst(); Long furture = system.currentTimemillis ()+mills; // How long does remaining = mills; While (pool.isempty ()&& Remaining >0){// Call the wait method with the pool. Remaining = furture-system.currentTimemillis (); // Remaining = furture- system.currentTimemillis (); } // Break out of the while loop, then there are two situations (either the CPU is successfully fetched, the connection pool is fetched, or the waiting time is over, return an empty connection, return the caller, and tell him, He missed and time ran out. // When you grab a CPU, you need to grab something from the connection pool. if (! pool.isEmpty()){ connection = pool.removeFirst(); } return connection; }}}}Copy the code
-
DBTest.java
package cn.enjoyedu.ch1.pool; import java.sql.Connection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; */ public class DBPoolTest {static DBPool pool = new DBPool(20); Static CountDownLatch end static CountDownLatch end static CountDownLatch end Public static void main(String[] args) throws Exception {// Number of threads int threadCount = 50; end = new CountDownLatch(threadCount); int count = 20; AtomicInteger got = new AtomicInteger(); NotGot = new AtomicInteger(); For (int I = 0; i < threadCount; i++) { Thread thread = new Thread(new Worker(count, got, notGot), "worker_"+i); thread.start(); } end.await(); // The main thread waits for system.out.println (" threadCount * count) "); System.out.println(" get connections: "+ got); System.out.println(" failed to connect: "+ 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 { NotGot Connection Connection = pool.fetchConnection(1000); if (connection ! = null) {try {/ / take after connection, database connection. The operation createStatement (); connection.commit(); } finally {// The connection is finished, then the connection is put back into the database connection pool pool.releaseconnection (connection); // incrementAndGet(); Notgot.incrementandget ();}} else {// When this gets the link to the spacetime, count these failures after the problem notgot.incrementandGet (); System.out.println(thread.currentThread ().getName() +" Wait for timeout!" ); } } catch (Exception ex) { } finally { count--; } } end.countDown(); }}}Copy the code
-
Sqlconnectimpl. Java overwrites a large number of methods
``` package cn.enjoyedu.ch1.pool; import cn.enjoyedu.tools.SleepTools; import java.sql.*; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; /** *类说明: */ public class SqlConnectImpl implements Connection{ /*拿一个数据库连接*/ public static final Connection fetchConnection(){ return new SqlConnectImpl(); } @Override public boolean isWrapperFor(Class<?> arg0) throws SQLException { // TODO Auto-generated method stub return false; } @Override public <T> T unwrap(Class<T> arg0) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void abort(Executor arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void clearWarnings() throws SQLException { // TODO Auto-generated method stub } @Override public void close() throws SQLException { // TODO Auto-generated method stub } @Override public void commit() throws SQLException { SleepTools.ms(70); } @Override public Array createArrayOf(String arg0, Object[] arg1) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Blob createBlob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Clob createClob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public NClob createNClob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public SQLXML createSQLXML() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Statement createStatement() throws SQLException { SleepTools.ms(1); return null; } @Override public Statement createStatement(int arg0, int arg1) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Statement createStatement(int arg0, int arg1, int arg2) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Struct createStruct(String arg0, Object[] arg1) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean getAutoCommit() throws SQLException { // TODO Auto-generated method stub return false; } @Override public String getCatalog() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Properties getClientInfo() throws SQLException { // TODO Auto-generated method stub return null; } @Override public String getClientInfo(String arg0) throws SQLException { // TODO Auto-generated method stub return null; } @Override public int getHoldability() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public DatabaseMetaData getMetaData() throws SQLException { // TODO Auto-generated method stub return null; } @Override public int getNetworkTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public String getSchema() throws SQLException { // TODO Auto-generated method stub return null; } @Override public int getTransactionIsolation() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { // TODO Auto-generated method stub return null; } @Override public SQLWarning getWarnings() throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isClosed() throws SQLException { // TODO Auto-generated method stub return false; } @Override public boolean isReadOnly() throws SQLException { // TODO Auto-generated method stub return false; } @Override public boolean isValid(int arg0) throws SQLException { // TODO Auto-generated method stub return false; } @Override public String nativeSQL(String arg0) throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String arg0) throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String arg0, int arg1, int arg2) throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String arg0, int arg1, int arg2, int arg3) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String arg0) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String arg0, int arg1) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String arg0, int[] arg1) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String arg0, String[] arg1) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String arg0, int arg1, int arg2) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String arg0, int arg1, int arg2, int arg3) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void releaseSavepoint(Savepoint arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void rollback() throws SQLException { // TODO Auto-generated method stub } @Override public void rollback(Savepoint arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setAutoCommit(boolean arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setCatalog(String arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setClientInfo(Properties arg0) throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public void setClientInfo(String arg0, String arg1) throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public void setHoldability(int arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setNetworkTimeout(Executor arg0, int arg1) throws SQLException { // TODO Auto-generated method stub } @Override public void setReadOnly(boolean arg0) throws SQLException { // TODO Auto-generated method stub } @Override public Savepoint setSavepoint() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Savepoint setSavepoint(String arg0) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setSchema(String arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setTransactionIsolation(int arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setTypeMap(Map<String, Class<?>> arg0) throws SQLException { // TODO Auto-generated method stub } } ``` Copy the code
-
-
The effect of methods on locks
-
yield()
- Summary: Calling this only cedes execution rights to the CPU and does not release the lock held by the current thread
-
sleep()
-
Overview: Thread sleep, lock not released,
-
Scene:
- One thread, sleep, get the lock first
- The other thread does not sleep to pick up the lock
-
Results:
- A thread that does not sleep can acquire the lock only after it has hibernated and executed the synchronized code block
-
Run screenshot:
-
Test code:
package cn.enjoyedu.ch1.base; */ Public class SleepLock {private Object lock = new Object(); public static void main(String[] args) { SleepLock sleepTest = new SleepLock(); Thread threadA = sleepTest.new ThreadSleep(); threadA.setName("ThreadSleep"); Thread threadB = sleepTest.new ThreadNotSleep(); threadB.setName("ThreadNotSleep"); threadA.start(); try { Thread.sleep(1000); System.out.println(" Main slept!" ); } catch (InterruptedException e) { e.printStackTrace(); } threadB.start(); } private class ThreadSleep extends Thread{ @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+" will take the lock"); try { synchronized(lock) { System.out.println(threadName+" taking the lock"); Thread.sleep(5000); System.out.println("Finish the work: "+threadName); } } catch (InterruptedException e) { //e.printStackTrace(); } } } private class ThreadNotSleep extends Thread{ @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+" will take the lock time="+System.currentTimeMillis()); synchronized(lock) { System.out.println(threadName+" taking the lock time="+System.currentTimeMillis()); System.out.println("Finish the work: "+threadName); }}}}Copy the code
-
-
wait()
- A thread that calls wait releases its own lock and, when awakened, contests the lock and executes the following code
-
notify/notifyAll
- There is no effect on locks, which are generally not released until the synchronization block is complete
- In use, it is generally placed in the last line;
-