盲猜是因为多线程引起的,公共变量没更新 为什么 求解?
直接上代码
/**
* 连接好的容器 使用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个回答
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));
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容