近日在基于Netty写异步HttpClient的时候,需要等http连接建立并通道打开后,才能使用该连接来发送数据,但是Netty中只能等待到连接建立就会返回一个用来收发数据的channel,如果channel并没有打开,用来发送数据时就会报错,因此需要在代码中等到channel打开后再返回,想到了使用简单的wait¬ify来解决,先上一段代码:
public class HttpClient{
private Boolean connected = false;
private final class InnerHandler extends SimpleChannelUpstreamHandler {
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
synchronized(connected){
connected = true;
channel = e.getChannel();
logger.debug("{}",this);
connected.notifyAll();
}
logger.debug("channelConnected");
}
}
public void connect() throws Exception {
......InnerHandler hander = new InnerHandler();......
ChannelFuture future = bootstrap.connect();
future.await();
synchronized(connected){
if (future.isSuccess() && !connected) {
logger.debug("connection opened,waiting for channel connected!");
logger.debug("{}", hander);
connected.wait();
}
logger.debug("new http client channel established!");
}
}
}
结果程序运行到connected.wait()便死锁了,经分析发现,connected.wait()和connected.notifyAll()进行操作的不是同一个对象,因为connected = true这里将connected 重新指向了另一个对象,代码上看来connected.notifyAll()没啥问题,其实这个信号已经没人收得到了,开始的那个connected.wait()也再也得不到任何信号,会一直等下去了。
修改代码,使用一个专门的对象来做锁:
private Object lockObject = new Object();
将synchronized、wait和notifyAll使用的对象都换为lockObject,一切正常。可见,使用对象锁的时候,尽量使用一个不会被潜在改变引用地址的对象做锁,最好专门新建一个Object来做锁。
当然只要保证synchronized、wait和notifyAll使用的是同一个对象,不专门弄个Object来做锁也是可以的,为了多搞点问题出来加深印象,将代码修改了一下:
public class HttpClient{
private boolean connected = false;
private final class InnerHandler extends SimpleChannelUpstreamHandler {
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
connected = true;
channel = e.getChannel();
synchronized(this){
logger.debug("notify:{}",this);
notifyAll();
}
logger.debug("channelConnected");
}
}
public void connect() throws Exception {
......InnerHandler hander = new InnerHandler();......
ChannelFuture future = bootstrap.connect();
future.await();
if (future.isSuccess() && !connected) {
logger.debug("connection opened,waiting for channel connected!");
synchronized(hander){
logger.debug("wait:{}", hander);
hander.wait();
}
logger.debug("new http client channel established!");
}
}
}
使用hander对象来做锁,这儿的代码已经确保大家使用的都是同一个hander,运行代码,发现一切正常,再运行几次,发现又死锁了,分析debug信息:
connection opened,waiting for channel connected!
notify: com.skymobi.http.HttpClient$InnerHandler@cc52fc
channelConnected
wait: com.skymobi.http.HttpClient$InnerHandler@cc52fc
原来程序执行时先跑去notify,然后再wait了,开始时不是很清楚为啥一定要加个synchronized,只是不加的话就不能用来wait,于是囫囵吞枣的加上个synchronized。这儿看来,加上synchronized应该是获取到锁,然后修改某些状态值,供别的线程根据这些状态值去判断是否需要做某些事情,一般synchronized中如果要使用wait,都需要先判断是否满足需要wait的条件,否则就会导致死锁,而在notify的synchronized代码片段中,一般会对判断条件使用的值进行修改,然后再通知wait的线程。
最后修改过能运行的代码如下:
public class HttpClient{
private boolean connected = false;
private final class InnerHandler extends SimpleChannelUpstreamHandler {
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
synchronized(this){
connected = true;
channel = e.getChannel();
logger.debug("notify:{}",this);
notifyAll();
}
logger.debug("channelConnected");
}
}
public void connect() throws Exception {
......InnerHandler hander = new InnerHandler();......
ChannelFuture future = bootstrap.connect();
future.await();
synchronized(hander){
if (future.isSuccess() && !connected) {
logger.debug("connection opened,waiting for channel connected!");
logger.debug("wait:{}", hander);
hander.wait();
}
logger.debug("new http client channel established!");
}
}
}
分享到:
相关推荐
在Java中,`wait()`, `notify()`, 和 `notifyAll()` 是Java Object类的三个方法,它们在实现线程间通信和协作时扮演着关键角色。这些方法主要用于解决线程等待和唤醒的问题,是基于Java Monitor(监视器)模型的。 ...
Java中的wait/notify/notifyAll可用来实现线程间通信,是Object类的方法,这三个方法都是native方法,是平台相关的,常用来实现生产者/消费者模式。 wait()方法将当前线程置于等待状态,直到其他线程调用notify()或...
在Java多线程编程中,wait和notify是两个非常重要的方法,它们都是Object类的方法,用于线程之间的通信和同步。下面我们将详细解释wait和notify的用法。 wait方法 wait方法是Object类的一个方法,用于让当前线程...
`wait()`、`notify()`和`notifyAll()`是Java中的三个关键字,它们属于Object类的方法,主要用于线程间的通信,尤其在实现生产者消费者模式时发挥着重要作用。本文将深入探讨这些方法以及如何在实际场景中应用它们。 ...
JAVAWAIT和NOTIFY的用法.pdf
在Java中,`wait()` 和 `notify()` 方法是实现线程间通信和协作的重要工具,它们属于 `java.lang.Object` 类,这意味着所有类都默认继承了这两个方法。本文将详细探讨如何使用 `wait()` 和 `notify()` 来控制子线程...
`synchronized`关键字、`wait()`和`notify()`方法是Java多线程中用于控制并发访问共享资源的重要工具,它们是Java内存模型(JMM)的一部分,主要用于解决线程间的同步问题。 一、`synchronized`关键字 `...
在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。。举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓冲区中有内容待...
在Java的多线程编程中,`notify()`与`wait()`是实现线程间通信的重要方法,它们主要用于解决生产者消费者问题、读者写者问题等典型同步问题。这两个方法定义在`Object`类中,因此所有Java对象都可以作为锁来使用。在...
3. 由于 wait()、notify/notifyAll() 在synchronized 代码块执行,说明当前线程一定是获取了锁的。 4. wait() 需要被try catch包围,中断也可以使wait等待的线程唤醒。 5. notify 和wait 的顺序不能错,如果A线程先...
标题和描述概述的知识点主要集中在Java的多线程机制中,特别是`wait`和`notify`方法在同步锁中的应用。这些方法对于控制线程之间的交互至关重要,尤其是在资源有限或需要确保数据一致性的情况下。 ### Java同步锁...
在Java多线程编程中,wait和notify是两个非常重要的机制,用于实现线程之间的通信和同步。在本文中,我们将通过示例代码详细介绍Java多线程wait和notify的使用,帮助读者更好地理解和掌握这两个机制。 wait机制 在...
源码—Java多线程5—死锁和wait notify notifyAll
通过本示例代码的学习,我们可以深入了解`wait()`与`notify()`方法的工作原理及其在Java多线程编程中的应用。这两个方法通过释放和重新获取锁的方式,有效地实现了线程间的通信和同步,是Java并发控制的重要组成部分...
在Java编程语言中,`wait()`和`notify()`是Object类中的两个关键方法,它们用于线程间的协作和通信。这两个方法在多线程环境下尤其重要,因为它们允许线程等待特定条件并通知其他线程继续执行。在分析给定的程序之前...
Java程序并发的Wait-Notify机制是Java多线程编程中的一种重要同步工具,它允许线程之间通过共享对象进行通信和协作。这个机制基于Java的内置锁(也称为监视器锁),通常与`synchronized`关键字一起使用。在Java中,`...
这些题目反映了310-065考试的重点,包括但不限于:Java基础语法、异常处理、多线程编程(并发和同步)、对象监视器和wait/notify机制。考生在准备考试时,需要深入理解这些概念,并能够编写和分析实际的Java代码以...
Java中的多线程协同工作是通过一系列的同步机制来实现的,其中wait、notify和notifyAll是基于对象监视器的同步原语。这些方法在Java的Object类中定义,主要用于线程间的通信和协作,确保资源的安全访问。下面将详细...
wait()、notify()和notifyAll()方法2---马克-to-win java视频
Java中的多线程设计涉及到许多核心概念,其中wait/notify机制是实现线程间通信和协作的关键工具。这个机制主要用于解决资源的分配和同步问题,它依赖于Java的内置锁机制,即`synchronized`关键字和对象锁。 首先,...