java 简单 SocketPool
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的更多相关文章
- java简单词法分析器(源码下载)
java简单词法分析器 : http://files.cnblogs.com/files/hujunzheng/%E7%AE%80%E5%8D%95%E8%AF%8D%E6%B3%95%E5%88%8 ...
- !!转!!java 简单工厂模式
举两个例子以快速明白Java中的简单工厂模式: 女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人.”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面.女娲造人,这就是 ...
- JAVA简单Swing图形界面应用演示样例
JAVA简单Swing图形界面应用演示样例 package org.rui.hello; import javax.swing.JFrame; /** * 简单的swing窗体 * @author l ...
- 多元线性回归----Java简单实现
http://www.cnblogs.com/wzm-xu/p/4062266.html 多元线性回归----Java简单实现 学习Andrew N.g的机器学习课程之后的简单实现. 课程地址:h ...
- java简单数据类型转化
java简单数据类型,有低级到高级为:(byte,short,char)→int→long→float→double (boolean不参与运算转化) 转化可以分为 低级到高级的自动转化 高级到低级的 ...
- 预防和避免死锁的方法及银行家算法的java简单实现
预防死锁 (1) 摒弃"请求和保持"条件 基本思想:规定所有进程在开始运行之前,要么获得所需的所有资源,要么一个都不分配给它,直到所需资源全部满足才一次性分配给它. 优点:简单.易 ...
- Java简单聊天室
实现Java简单的聊天室 所用主要知识:多线程+网络编程 效果如下图 /** * * @author Administrator * * 简单的多人聊天系统——重点:同时性,异步性 * 1.客户端:发 ...
- Java简单工厂模式
Java简单工厂模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述简单工厂模式的:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简 ...
- java简单web爬虫(网页图片)
java简单web爬虫(网页图片)效果,执行main()方法后图片就下载道C盘的res文件夹中.没有的话创建一个文件夹代码里的常量根据自己的需求修改,代码附到下面. package com.sinit ...
随机推荐
- Linux系统之-常用命令及技巧
一. 通用命令:1.date :print or set the system date and time2. stty -a: 可以查看或者打印控制字符(Ctrl-C, Ctrl-D, Ctrl-Z ...
- linux系统一些信息(待整理)
Linux查看物理CPU个数.核数.逻辑CPU个数 复制代码 # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 ...
- python re模块常用的正则表达式
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r&qu ...
- JS-日期和时间
# 格式化日期和时间 扩展 Date: Date.prototype.format = function(format){ var o = { "M+" : this.getMon ...
- %matplotlib inline 被注释掉后,pycharm不能生成图
目录 问题描述 解决方案 @ 问题描述 在 jupyter 编译器中 程序的开头,有这么一行 %matplotlib inline import numpy as np import matplotl ...
- 31. Git与Github
Github介绍 GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名gitHub. GitHub于2008年4月10日正式上线,除了Git代码仓库 ...
- Intellij IDEA 安装Scala插件 + 创建Scala项目
一.IDEA 2018 Ultimate edition (旗舰破解版下载地址) 百度网盘地址:https://pan.baidu.com/s/1d9ArRH6adhDUGiJvRqnZMw 二.I ...
- vue父组件与子组件之间的数据传递
父组件向子组件传递数据 父组件用数据绑定:子组件用props接收 <!-- test-vue-model父组件 --> <template> <div> <m ...
- 单机zookeeper部署伪集群
1.zookeeper介绍 ZooKeeper 是一个为分布式应用所设计的分布的.开源的协调服务.分布式的应用可以建立在同步.配置管理.分组和命名等服务的更高级别的实现的基础之上. ZooKeeper ...
- JFreeChart教程
图表是信息的图形表示.有可用的各种工具,它可用于创建不同类型的图表. 本教程学习什么是JFreeChart?为什么需要它,并在各种方式列出一个基于Java的应用程序或独立创建不同类型的图表. JFre ...