wait/notify模拟连接池

连接池中的连接可重复使用,减少每次新建和烧毁连接对资源的消耗,但连接池的容量大小也要设置合理,否则也会占用多余的资源。连接池的基本功能是获取连接和释放连接

连接在java中也是一个类,连接对象是一个普通java对象,连接池也是如此,本例使用Connection代表连接类,ConnectionPool代表连接池,主要用到的技术为wait/notify机制以及CountDownLatch的使用

第一版的代码

日志使用的为log4j2,配置内容直接拷贝官网内容,将日志级别改为了info,并去掉了一些不必要的打印

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="Info">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>
View Code

连接池ConnectionPool

package com.demo.Multithreading.ConnectionPool;

import java.util.LinkedList;

public class ConnectionPool {
    // 存放连接
    private LinkedList<Connection> pool = new LinkedList<Connection>();
    // 连接池的初始容量
    private int capacity;

    public ConnectionPool() {
        capacity = 10;
        init();
    }

    public ConnectionPool(int capacity) {
        this.capacity = capacity;
        init();
    }

    /**
     * 初始化连接池
     */
    public void init() {
        for (int i = 0; i < capacity; i++) {
            pool.add(Connection.createConnection(i));
        }
    }

    /**
     * 获取连接,指定的时间内未获取到,则返回null
     * 
     * @param timeout
     *            等待超时时间
     * @return
     * @throws InterruptedException
     */
    public Connection getConnection(long timeout) throws InterruptedException {
        synchronized (pool) {
            if (pool.size() == 0) {
                // 连接池为空,在指定时间内等待以获取连接
                pool.wait(timeout);
                // 收到其他线程notify,准备获取连接
                if (pool.size() > 0) {
                    // 连接池中存在连接可获取
                    Connection removeFirst = pool.removeFirst();
                    return removeFirst;
                }
                // 未获取到连接,返回null
                return null;
            } else {
                // 连接池中存在连接,直接获取
                Connection removeFirst = pool.removeFirst();
                return removeFirst;
            }
        }
    }

    /**
     * 释放连接
     * 
     * @param con
     */
    public void releaseConnection(Connection con) {
        synchronized (pool) {
            if (con != null) {
                // 在末尾添加连接
                pool.addLast(con);
                // 通知其他线程获取连接
                pool.notifyAll();
            }
        }
    }
}
View Code

连接Connection

package com.demo.Multithreading.ConnectionPool;

public class Connection {

    private int num;

    private Connection(int num) {
        this.num = num;
    }

    public static Connection createConnection(int num) {
        return new Connection(num);
    }

    @Override
    public String toString() {
        return "Connection [num=" + num + "]";
    }

}
View Code

测试时线程类MyThread

package com.demo.Multithreading.ConnectionPool.test;

import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.demo.Multithreading.ConnectionPool.Connection;
import com.demo.Multithreading.ConnectionPool.ConnectionPool;

public class MyThread extends Thread {
    private Logger logger = LoggerFactory.getLogger(MyThread.class);
    private ConnectionPool pool;
    private CountDownLatch latch;

    public MyThread(String name, CountDownLatch latch, ConnectionPool pool) {
        this.pool = pool;
        this.latch = latch;
        this.setName(name);
    }

    @Override
    public void run() {
        Connection connection = null;
        try {
            connection = pool.getConnection(5000);
            Thread.sleep(2000);
            logger.info(Thread.currentThread().getName() + ": " + connection);
        } catch (InterruptedException e) {
            logger.error("", e);
        }

        latch.countDown();
    }

}
View Code

测试类App

package com.demo.Multithreading;

import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.demo.Multithreading.ConnectionPool.ConnectionPool;
import com.demo.Multithreading.ConnectionPool.test.MyThread;

public class App {
    private static Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        ConnectionPool cp = new ConnectionPool(3);
        int threadCount = 5;
        CountDownLatch cd = new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            MyThread th = new MyThread("mythread" + i, cd, cp);
            th.start();
        }

        try {
            cd.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("execute end.");
    }
}
View Code

执行测试类中main方法,输出结果如下

11:23:45.307 [mythread0] mythread0: Connection [num=0]
11:23:45.307 [mythread2] mythread2: Connection [num=2]
11:23:45.307 [mythread1] mythread1: Connection [num=1]
11:23:50.293 [mythread3] mythread3: null
11:23:50.294 [mythread4] mythread4: null
11:23:50.294 [main] execute end.

连接池中初始化3个连接,5个线程同时获取连接,有两个连接未获取到连接池,在MyThread中获取连接的最大时间为5秒,线程休眠2秒,可认为线程执行时间为2秒,既然如此,最开始获取到连接的三个线程在2秒左右,不超过3秒的时间内一定能执行结束,另外两条线程也能获取到连接,但真实输出结果是,后面两个线程未获取到连接,究其原因,还是因为没有释放连接。对于可复用资源,比如连接池,线程池等,也包括java io流,在使用之后一定要记得关闭。

修改测试线程MyThread中run方法,释放连接

package com.demo.Multithreading.ConnectionPool.test;

import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.demo.Multithreading.ConnectionPool.Connection;
import com.demo.Multithreading.ConnectionPool.ConnectionPool;

public class MyThread extends Thread {
    private Logger logger = LoggerFactory.getLogger(MyThread.class);
    private ConnectionPool pool;
    private CountDownLatch latch;

    public MyThread(String name, CountDownLatch latch, ConnectionPool pool) {
        this.pool = pool;
        this.latch = latch;
        this.setName(name);
    }

    @Override
    public void run() {
        Connection connection = null;
        try {
            connection = pool.getConnection(5000);
            Thread.sleep(2000);
            logger.info(Thread.currentThread().getName() + ": " + connection);
        } catch (InterruptedException e) {
            logger.error("", e);
        } finally {
            if (connection != null) {
                pool.releaseConnection(connection);
            }
        }

        latch.countDown();
    }

}
View Code

执行结果

11:39:53.906 [mythread1] mythread1: Connection [num=1]
11:39:53.906 [mythread0] mythread0: Connection [num=0]
11:39:53.906 [mythread2] mythread2: Connection [num=2]
11:39:55.914 [mythread3] mythread3: null
11:39:55.914 [mythread4] mythread4: Connection [num=1]
11:39:55.915 [main] execute end.

有线程依然未获取到连接

猜你喜欢

转载自www.cnblogs.com/qq931399960/p/10868505.html
今日推荐