Never awaitUninterruptibly() on Netty Channels
来源:互联网 发布:淘宝店铺 花呗 编辑:程序博客网 时间:2024/06/08 01:36
05.03 | Never awaitUninterruptibly() on Netty Channels
TL:DR; When acquiring Channels in Netty, always use a ChannelFutureListenerand never awaitUninterruptibly(). Curious why? Read on.
In the Java SDK for Couchbase, we use Netty to establish and maintain a streaming connection to one of the cluster nodes in order to get notified when topology changes happen. This streaming connection needs to be established during the bootstrap process of the client and we need to block until the connection is established (actually we don't need to, but the current implementation works that way). The old implementation to acquire the Channel looked like this:
- ClientBootstrap bootstrap = new ClientBootstrap(factory);
- bootstrap.setPipelineFactory(new BucketMonitorPipelineFactory());
- ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
- channel = future.awaitUninterruptibly().getChannel();
- if(!future.isSuccess()){
- bootstrap.releaseExternalResources();
- thrownew ConnectionException("Something bad happened...");
- }
This works great, but there is a problem associated that is not obvious in the first place. As long as you use this code only in a client side context, Netty will not complain and happily work with your code. When people started to use our client library inside a Netty based server framework (for example Play), Netty complained like this:
Unexpected exception[IllegalStateException: await*() in I/O thread causes a dead lock or sudden performance drop.Use addListener() instead or call await*() from a different thread.]
The environment where this happens is clearly defined: we are bootstrapping a Netty client inside the I/O thread of a Netty server, so we basically have two Netty environments running and one is complaining about the other. Once you are aware of this situation, it is more or less easy to fix:
- bootstrap = new ClientBootstrap(factory);
- bootstrap.setPipelineFactory(new BucketMonitorPipelineFactory());
- ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
- channelFuture.addListener(new ChannelFutureListener(){
- @Override
- public void operationComplete(ChannelFuture cf) throws Exception {
- if(cf.isSuccess()){
- channel = cf.getChannel();
- }else {
- bootstrap.releaseExternalResources();
- thrownew ConnectionException("Something bad happened...");
- }
- }
- });
Now, instead of waiting on the caller thread, we move the waiting part to a separate thread managed by the Netty execution context. There's only one problem left: we still need to block, because the code down the stack depends on a established Channel to work with. To solve this issue, we can use aCountDownLatch like this:
- final CountDownLatch channelLatch= new CountDownLatch(1);
- channelFuture.addListener(new ChannelFutureListener(){
- @Override
- public void operationComplete(ChannelFuture cf) throws Exception {
- if(cf.isSuccess()){
- channel = cf.getChannel();
- channelLatch.countDown();
- }else {
- bootstrap.releaseExternalResources();
- thrownew ConnectionException("Something bad happened...");
- }
- }
- });
- try {
- channelLatch.await();
- } catch(InterruptedException ex){
- thrownew ConnectionException("Interrupted while waiting for streaming "
- +"connection to arrive.");
- }
In the end we still block on the caller thread, but we are compliant with Netty. The main takeaway for me is that you should never block on acquiring Channels in Netty, just because of the fact that your client side code may be used in a server side context as well. This is especially true for library developers like me.
原文出处:http://nitschinger.at/Never-await-Uninterruptibly-on-Netty-Channels
- Never awaitUninterruptibly() on Netty Channels
- Netty: 注意不要为java.nio.channels.ClosedChannelException浪费时间
- Netty HTTP on Android
- I will never given up```Come on...
- never
- 10 things you should never do on a consulting job
- close() was never explicitly called on databaseandroid.database.sqlite异常
- FAQ_21 sqlite exception: close() was never explicitly called on database
- 处理AndroidSQLite-close()was never explicitly called on database异常
- Never store the password unhased directly on the server!
- 8 Deadly Commands You Should Never Run on Linux
- Android SQLite - close() was never explicitly called on database
- close() was never explicitly called on database,SQLiteMisuseException
- android SQLite :close() was never explicitly called on database 'XXXXXX'
- SQLite: close() was never explicitly called on database
- hive运行报Call to master/**.** failed on local exception: java.nio.channels.ClosedByInterr
- 通道 Channels
- Configuring Channels
- DBA应该知道的RAID卡知识
- Poj 3422(最小费用流)
- 编程实现二叉树的建立,前序遍历,中序遍历和后续遍历
- 黑马程序员 异常
- 【D3.js数据可视化系列教程】--(七)SVG初探
- Never awaitUninterruptibly() on Netty Channels
- Map
- 《唐老师C++》之const引用
- 误把main()函数写成mian()函数竟然通过编译
- Hdu 1597 find the nth digit
- Linux container介绍
- CSS背景图坐标定位详解,为什么会有负数?
- 【CVTE2014校园招聘.在线测试】01.数据库密码加密
- HDU 2037 今年暑假不AC (贪心---求最多不相交区间问题)