创建es单例

用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的对象都是一个实例,而不是多个线程拥有一个实例

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值