1、在OKHttp中需要一个队列来保存不同的请求
/**
* 保存HttpConnection队列
*/
private Deque<HttpConnection> mConnections = new ArrayDeque<>();
2、在每次请求前从线程池里检查是否有超时的连接,将超时的连接从线程池移除
//在这里将连接放入线程池
public void put(HttpConnection httpConnection) {
if (!cleanupRunning) {
cleanupRunning = true;
EXECUTOR.execute(cleanupRunnable);
}
mConnections.add(httpConnection);
}
/**
* 清理线程
*/
private Runnable cleanupRunnable = () -> {
while(true) {
//等待再次检查时间间隔
long waitTime = cleanup(System.currentTimeMillis());
if(waitTime == -1) {
return;
}
if(waitTime > 0) {
synchronized (ConnectionPool.this){
try {
ConnectionPool.this.wait(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
//在这里清理超时请求
private long cleanup(long nowTime) {
//记录最长闲置时间
long longLastIdlTime = -1;
synchronized (this) {
//遍历连接队列
Iterator<HttpConnection> iterator = mConnections.iterator();
while (iterator.hasNext()) {
HttpConnection next = iterator.next();
//闲置时间
long idlDurationTime = nowTime - next.getLastUseTime();
if (idlDurationTime > keepAlive) {
iterator.remove();
next.close();
Log.d(TAG, "cleanup —> 超过闲置时间,移出线程池");
continue;
}
//最长的闲置时间
if (longLastIdlTime < idlDurationTime) {
longLastIdlTime = idlDurationTime;
}
}
//返回等待时间
if (longLastIdlTime >= 0) {
return keepAlive - longLastIdlTime;
}
//连接池没有连接,可以退出
cleanupRunning = false;
return longLastIdlTime;
}
}
3、清理线程由线程池管理并将线程设为守护线程
/**
* 定义一个线程池,用来执行清理线程
*/
private static final Executor EXECUTOR
= new ThreadPoolExecutor(
0, //最小并发线程数。
Integer.MAX_VALUE, //线程池中允许的最大线程数
60L, //当线程的数目大于corePoolSize时,线程的最大存活时间。
TimeUnit.SECONDS, //时间单位
new SynchronousQueue<>(),//在执行任务之前用于保存任务的队列
r -> {//创建新的线程使用的工厂
Thread thread = new Thread(r, "ConnectionPool");
thread.setDaemon(true);
return thread;
});
4、线程池的复用,遍历请求队列的请求,判断是否有相同的请求
/**
* 获得可复用的连接池
*
* @param host
* @param port
* @return
*/
public HttpConnection get(String host, int port) {
Iterator<HttpConnection> iterator = mConnections.iterator();
while (iterator.hasNext()) {
HttpConnection next = iterator.next();
//判断线程池里是否存在相同的请求地址
if (next.isSameAdress(host, port)) {
iterator.remove();
return next;
}
}
return null;
}
public boolean isSameAdress(String host, int port) {
if (TextUtils.isEmpty(host) || port < 0) {
throw new NullPointerException("Host OR Port maybe null point,Please Check it once again");
}
if (mSocket == null) {
return false;
}
return TextUtils.equals(host, mSocket.getInetAddress().getHostName()) && port == mSocket.getPort();
}