package org.rx.socks;

import lombok.extern.slf4j.Slf4j;
import org.rx.common.LogWriter;
import org.rx.common.NQuery;
import org.rx.beans.DateTime; import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket; import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque; import static org.rx.common.Contract.require; @Slf4j
public final class SocketPool extends Traceable implements AutoCloseable {
public static final class PooledSocket implements AutoCloseable {
private final SocketPool owner;
private DateTime lastActive;
public final Socket socket; public boolean isConnected() {
return !owner.isClosed() && !socket.isClosed() && socket.isConnected();
} public DateTime getLastActive() {
return lastActive;
} public void setLastActive(DateTime lastActive) {
this.lastActive = lastActive;
} private PooledSocket(SocketPool owner, Socket socket) {
this.owner = owner;
this.socket = socket;
lastActive = DateTime.utcNow();
} @Override
public void close() {
owner.returnSocket(this);
}
} public static final SocketPool Pool = new SocketPool();
private static final int DefaultConnectTimeout = 30000;
private static final int DefaultMaxIdleMillis = 120000;
private static final int DefaultMaxSocketsCount = 64;
private final ConcurrentHashMap<InetSocketAddress, ConcurrentLinkedDeque<PooledSocket>> pool;
private volatile int connectTimeout;
private volatile int maxIdleMillis;
private volatile int maxSocketsCount;
private final Timer timer;
private volatile boolean isTimerRun; public int getConnectTimeout() {
return connectTimeout;
} public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
} public int getMaxIdleMillis() {
return maxIdleMillis;
} public void setMaxIdleMillis(int maxIdleMillis) {
if (maxIdleMillis <= 0) {
maxIdleMillis = DefaultMaxIdleMillis;
}
this.maxIdleMillis = maxIdleMillis;
} public int getMaxSocketsCount() {
return maxSocketsCount;
} public void setMaxSocketsCount(int maxSocketsCount) {
if (maxSocketsCount < 0) {
maxSocketsCount = 0;
}
this.maxSocketsCount = maxSocketsCount;
} private SocketPool() {
pool = new ConcurrentHashMap<>();
connectTimeout = DefaultConnectTimeout;
maxIdleMillis = DefaultMaxIdleMillis;
maxSocketsCount = DefaultMaxSocketsCount;
String n = "SocketPool";
timer = new Timer(n, true);
LogWriter tracer = new LogWriter();
tracer.setPrefix(n + " ");
tracer.info("started..");
setTracer(tracer);
} @Override
protected void freeObjects() {
clear();
} private void runTimer() {
if (isTimerRun) {
return;
}
synchronized (timer) {
if (isTimerRun) {
return;
} long period = 90000;
timer.schedule(new TimerTask() {
@Override
public void run() {
clearIdleSockets();
}
}, period, period);
isTimerRun = true;
}
getTracer().info("runTimer..");
} private void clearIdleSockets() {
for (Map.Entry<InetSocketAddress, ConcurrentLinkedDeque<PooledSocket>> entry : NQuery.of(pool.entrySet())) {
ConcurrentLinkedDeque<PooledSocket> sockets = entry.getValue();
if (sockets == null) {
continue;
} for (PooledSocket socket : NQuery.of(sockets)) {
if (!socket.isConnected()
|| DateTime.utcNow().subtract(socket.getLastActive()).getTotalMilliseconds() >= maxIdleMillis) {
sockets.remove(socket);
getTracer().info("clear idle socket[local=%s, remote=%s]..",
Sockets.getId(socket.socket, false), Sockets.getId(socket.socket, true));
}
}
if (sockets.isEmpty()) {
pool.remove(entry.getKey());
}
}
if (pool.size() == 0) {
stopTimer();
}
} private void stopTimer() {
synchronized (timer) {
timer.cancel();
timer.purge();
isTimerRun = false;
}
getTracer().info("stopTimer..");
} private ConcurrentLinkedDeque<PooledSocket> getSockets(InetSocketAddress remoteAddr) {
ConcurrentLinkedDeque<PooledSocket> sockets = pool.get(remoteAddr);
if (sockets == null) {
pool.put(remoteAddr, sockets = new ConcurrentLinkedDeque<>());
runTimer();
}
return sockets;
} public PooledSocket borrowSocket(InetSocketAddress remoteAddr) {
checkNotClosed();
require(remoteAddr); boolean isExisted = true;
ConcurrentLinkedDeque<PooledSocket> sockets = getSockets(remoteAddr);
PooledSocket pooledSocket;
if ((pooledSocket = sockets.pollFirst()) == null) {
Socket sock = new Socket();
try {
sock.connect(remoteAddr, connectTimeout);
} catch (IOException ex) {
throw new SocketException(remoteAddr, ex);
}
pooledSocket = new PooledSocket(this, sock);
isExisted = false;
}
if (!pooledSocket.isConnected()) {
if (isExisted) {
sockets.remove(pooledSocket);
}
return borrowSocket(remoteAddr);
}
Socket sock = pooledSocket.socket;
getTracer().info("borrow %s socket[local=%s, remote=%s]..", isExisted ? "existed" : "new",
Sockets.getId(sock, false), Sockets.getId(sock, true));
return pooledSocket;
} public void returnSocket(PooledSocket pooledSocket) {
checkNotClosed();
require(pooledSocket); String action = "return";
try {
if (!pooledSocket.isConnected()) {
action = "discard closed";
return;
}
pooledSocket.setLastActive(DateTime.utcNow());
ConcurrentLinkedDeque<PooledSocket> sockets = getSockets(
(InetSocketAddress) pooledSocket.socket.getRemoteSocketAddress());
if (sockets.size() >= maxSocketsCount || sockets.contains(pooledSocket)) {
action = "discard contains";
return;
} sockets.addFirst(pooledSocket);
} finally {
Socket sock = pooledSocket.socket;
getTracer().info("%s socket[local=%s, remote=%s]..", action, Sockets.getId(sock, false),
Sockets.getId(sock, true));
}
} public void clear() {
checkNotClosed(); for (Socket socket : NQuery.of(pool.values()).selectMany(p -> p).select(p -> p.socket)) {
try {
getTracer().info("clear socket[local=%s, remote=%s]..", Sockets.getId(socket, false),
Sockets.getId(socket, true));
Sockets.close(socket);
} catch (Exception ex) {
log.error("SocketPool clear", ex);
}
}
pool.clear();
}
}

java 简单 SocketPool的更多相关文章

  1. java简单词法分析器(源码下载)

    java简单词法分析器 : http://files.cnblogs.com/files/hujunzheng/%E7%AE%80%E5%8D%95%E8%AF%8D%E6%B3%95%E5%88%8 ...

  2. !!转!!java 简单工厂模式

    举两个例子以快速明白Java中的简单工厂模式: 女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人.”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面.女娲造人,这就是 ...

  3. JAVA简单Swing图形界面应用演示样例

    JAVA简单Swing图形界面应用演示样例 package org.rui.hello; import javax.swing.JFrame; /** * 简单的swing窗体 * @author l ...

  4. 多元线性回归----Java简单实现

    http://www.cnblogs.com/wzm-xu/p/4062266.html 多元线性回归----Java简单实现   学习Andrew N.g的机器学习课程之后的简单实现. 课程地址:h ...

  5. java简单数据类型转化

    java简单数据类型,有低级到高级为:(byte,short,char)→int→long→float→double (boolean不参与运算转化) 转化可以分为 低级到高级的自动转化 高级到低级的 ...

  6. 预防和避免死锁的方法及银行家算法的java简单实现

    预防死锁 (1) 摒弃"请求和保持"条件 基本思想:规定所有进程在开始运行之前,要么获得所需的所有资源,要么一个都不分配给它,直到所需资源全部满足才一次性分配给它. 优点:简单.易 ...

  7. Java简单聊天室

    实现Java简单的聊天室 所用主要知识:多线程+网络编程 效果如下图 /** * * @author Administrator * * 简单的多人聊天系统——重点:同时性,异步性 * 1.客户端:发 ...

  8. Java简单工厂模式

    Java简单工厂模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述简单工厂模式的:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简 ...

  9. java简单web爬虫(网页图片)

    java简单web爬虫(网页图片)效果,执行main()方法后图片就下载道C盘的res文件夹中.没有的话创建一个文件夹代码里的常量根据自己的需求修改,代码附到下面. package com.sinit ...

随机推荐

  1. AcWing 231. 天码 (容斥)打卡

    题目:https://www.acwing.com/problem/content/233/ 题意:给你n个不同的数,让你选取一个四元组,gcd为1,让你求这样的四元组数量是多少 思路:我们单独直接去 ...

  2. express设置允许跨域访问该服务.

    const express = require('express');const app = express(); //设置允许跨域访问该服务.app.all('*', function (req, ...

  3. StaticInjectorError[Http]:

    报错:AppComponent.html:28 ERROR Error: StaticInjectorError[Http]: StaticInjectorError[Http]: 解决方法:

  4. Single Page Application

    single page web application,SPA,就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序.   单页Web应用(si ...

  5. 25. 服务器性能监控之nmon工具介绍

    nmon介绍: nmon是一个简单的性能监测工具,可以监测CPU.内存.网络等的使用情况. 步骤: 1.下载nmon(根据你的操作系统下载),地址 2.nmon文件部署到服务器中 3.启动nmon(注 ...

  6. list列表操作(创建、增加、删除、取值)

    list ####(一)列表的创建[].追加(append,extend,insert).删除(remove.del.poop).修改 ##创建一个空列表.一个字符串列表.一个数字列表 lis0 = ...

  7. Android组件内核之Activity调用栈分析(一)

    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680 导语 我们陈述一下Activity,Activity是整个应用用户交互的 ...

  8. Eclipse国内下载升级方法

    Eclipse国内下载升级方法 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} ...

  9. 给Laravel4添加中文语系(转)

    Laravel 4 官方不附带英文以外的 validataion 错误信息翻译. 今天发现GitHub 上有一个 repository 收集不同的翻译,大家可以下载需要的翻译. GitHub项目地址: ...

  10. python+tushare获取股票和基金每日涨跌停价格

    接口:stk_limit 描述:获取全市场(包含A/B股和基金)每日涨跌停价格,包括涨停价格,跌停价格等,每个交易日8点40左右更新当日股票涨跌停价格. 限量:单次最多提取4800条记录,可循环调取, ...