用es查询时起的线程多或者是请求过多,报了如下错误:
java.lang.IllegalStateException: failed to create a child event loop
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:88)
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:58)
...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.Throwable: failed to open a new selector
at io.netty.channel.nio.NioEventLoop.openSelector(NioEventLoop.java:175)
at io.netty.channel.nio.NioEventLoop.<init>(NioEventLoop.java:149)
at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:127)
at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:36)
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:84)
... 49 common frames omitted
Caused by: java.io.IOException: Too many open files
at sun.nio.ch.IOUtil.makePipe(Native Method)
at sun.nio.ch.EPollSelectorImpl.<init>(EPollSelectorImpl.java:65)
at sun.nio.ch.EPollSelectorProvider.openSelector(EPollSelectorProvider.java:36)
at io.netty.channel.nio.NioEventLoop.openSelector(NioEventLoop.java:173)
... 53 common frames omitted
猜测原因可能是因为创建的es连接太多了
之前以为实现了es单例模式 后来发现自己想多了。。。。。科科
/**
* Discribtion: 使用单例模式来初始化客户端,这样可以避免每次调用都都需要重复初始化建立链接和释放链接
*/
public class EsUtils {
//集群名,默认值elasticsearch
private static String CLUSTER_NAME;
//ES集群中某个节点
private static String HOSTNAME;
//连接端口号
private static int TCP_PORT;
//构建Settings对象 设置es集群名称并设置自动发现集群其他的节点
private static Settings settings = null;
//TransportClient对象,用于连接ES集群
//volatile的读和写建立了一个happens-before关系,类似于申请和释放一个互斥锁
private static volatile TransportClient client;
// private static TransportClient client;
private static AdminClient adminClient;
/**
* client = new PreBuiltTransportClient()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
* <p>
* 1:给 instance 分配内存
* 2:调用 Singleton 的构造函数来初始化成员变量
* 3:将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
* 但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,
* 最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,
* 这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。
* <p>
* 我们只需要将 instance 变量声明成 volatile 就可以了。
* 取操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况
* 。从「先行发生原则」的角度理解的话,就是对于一个 volatile 变量的写操作都先行发生于后面对这个变量的读操作
*
* @return
* @throws UnknownHostException
*/
public static TransportClient getSingletonClient() {
init();
if (null == client) {
synchronized (TransportClient.class) {
try {
client = new PreBuiltTransportClient(settings).addTransportAddress(
new TransportAddress(InetAddress.getByName(HOSTNAME), TCP_PORT));
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
return client;
}
public static TransportClient getClient() {
init();
try {
client = new PreBuiltTransportClient(settings).addTransportAddress(
new TransportAddress(InetAddress.getByName(HOSTNAME), TCP_PORT));
} catch (UnknownHostException e) {
e.printStackTrace();
}
return client;
}
private static void init() {
CLUSTER_NAME = "xiaoyao";
HOSTNAME = "192.168.88.126";
TCP_PORT = 9300;
settings =
Settings.builder().put("cluster.name", CLUSTER_NAME).put("client.transport.sniff", true)
.build();
}
public static void main(String[] args) {
Long before = System.currentTimeMillis();
//单例
System.out.println(getSingletonClient().hashCode());//1
System.out.println(getSingletonClient().hashCode());//1
System.out.println(getSingletonClient().hashCode());//1
//多例
System.out.println(getClient().hashCode());//2
System.out.println(getClient().hashCode());//2
System.out.println(getClient().hashCode());//2
Runnable runnable1 = new Runnable() {
@Override public void run() {
System.out.println("=====1======="+getSingletonClient().hashCode());
}
};
Runnable runnable2 = new Runnable() {
@Override public void run() {
System.out.println("======2========"+getClient().hashCode());
}
};
ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(6,10,5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
threadPoolExecutor1.execute(runnable1);
threadPoolExecutor1.execute(runnable1);
threadPoolExecutor1.execute(runnable1);
threadPoolExecutor1.execute(runnable1);
threadPoolExecutor1.execute(runnable1);
ThreadPoolExecutor threadPoolExecutor2 = new ThreadPoolExecutor(6,10,5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
threadPoolExecutor2.execute(runnable2);
threadPoolExecutor2.execute(runnable2);
threadPoolExecutor2.execute(runnable2);
threadPoolExecutor2.execute(runnable2);
threadPoolExecutor2.execute(runnable2);
}
}
运行main函数
824900551
824900551
824900551
1320869181
471004142
1050149826
=====1=======1050149826
=====1=======1050149826
=====1=======1050149826
=====1=======1050149826
=====1=======1050149826
======2========1598190758
======2========846380587
======2========1037549615
======2========1051933973
======2========1130786272
getSingletonClient()得到的是同一个实例,而getClient()方法没有实现单例,所以new出来的实例是不一样的
多线程的话runnable1实现的是单例,所以每个线程直接获取了main线程的实例(最后的那个实例),而runnable2每个线程获取不一样的实例
注释掉1和2 再运行
======2========443948702
======2========1670595299
======2========126538895
======1=======936331450
======2========1843903880
======2========190437971
======1=======171596003
======1=======1224624214
======1=======308938540
======1=======875698385
发现1 中的每个实例都不一样 当时觉得。。。。。
后来发现单例指的是在一个线程内new的对象都是一个实例,而不是多个线程拥有一个实例