盲猜是因为多线程引起的,公共变量没更新 为什么 求解?

作者站长头像
站长
· 阅读数 6

直接上代码

   /**
     * 连接好的容器 使用volatile也不行
     */
    private volatile ChannelFuture channelFuture;

    @PostConstruct
    public void start() {
        //初始化信息
        try {
            this.init();
        } catch (Exception e) {
            log.error("启动 netty 客户端出现异常", e);
        }
    }

    private void init() {
        synchronized (this) {
            //每次都需要重置通道
            if (mChannel.get("channel") != null) {
                mChannel.clear();
            }


            this.eventExecutors = new NioEventLoopGroup(1);

            //配置客户端的各种信息
            Bootstrap bootstrap = new Bootstrap();
            //设置线程组
            bootstrap.group(eventExecutors);

            //设置通道 此通道是异步非堵塞
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
            //初始化通道 其中在里面配置逻辑
            bootstrap.handler(new BdspNettySocketClientInitializer());
            //连接设备信息
            System.out.println("netty client start!");
            this.channelFuture = bootstrap.connect("127.0.0.1", 6666);
            this.channelFuture.addListener(new ConnectionListener());//这事防止客户端掉线 掉线后重连
        }
    }


    public void send(String msg) {
        try {
           //这里是我找到的解决方法 思路是拿到最新的通道
 //mChannel.get("channel").writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
//下面打印的地址第一次是一样的 当断线重启时 地址就不一样了
            System.out.println(mChannel.get("channel"));
            System.out.println(channelFuture.channel());
          //这个通道在我使用第一次启动时可以使用 当断开时多线程重启时就不能使用原因是 我打印了下通道的地址 发现地址并没有更新 尝试给启动的配置加锁还是拿不到最新的通道 十分不解
  channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
        } catch (Exception e) {
            log.error(this.getClass().getName().concat(".send has error"), e);

        }
    }

重启的调用方式

    private BdspNettySocketClient bdspNettySocketClient = new BdspNettySocketClient();

    private void reconnection(ChannelHandlerContext ctx) {
        log.info("3s之后重新建立连接");
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("进行重连客户端");
                bdspNettySocketClient.start();
            }
        }, 3L, TimeUnit.SECONDS);
    }

根据下方两位回答的都试了 还是不行取到的还是第一次存放的数据 至于我那个取到最新的那个做法我是利用ConcurrentHashMap每次都存放(每次覆盖操作) 这样就是取出最新的 盲猜是因为多线程引起的,公共变量没更新 为什么 求解?

找到问题关键了state 引发的血案下面的个人对上面发生这种情况的理解 同时也为以后避免这种情况能正确的采用成员变量还是类变量 自我反省

代码执行流程 你会发现类变量和对象属性的不同

​ 第一步:连接netty服务端 得到一个连接对象

​ 第二步:拿到连接对象ChannelFuture 得到通道 发送消息 所以将ChannelFuture 变成类变量还是成员变量

​ 第三步:写一个发送的方法通过拿到的连接对象ChannelFuture发送消息

​ 第四步:完成当服务端断开后进行重连操作 (第二步选不对就会影响后面发送操作)

解释:

​ 1. 若采用成员变量则 保证调用发送消息的那个对象和操作重连的是同一个对象 否则你将拿不到最新的ChannelFuture(也就是重连后的连接对象) 只能拿到第一次初始化的旧变量

​ 2.若采用类变量则就不用考虑是不是同一个对象了

回复
1个回答
avatar
test
2024-06-30
private AtomicReference<ChannelFuture> channelFutureRef = new AtomicReference<>();


this.channelFutureRef.set(bootstrap.connect("127.0.0.1", 6666));

ChannelFuture channelFuture = channelFutureRef.get();
channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容