1.Dubbo调用超时那些事儿
2.Java日期时间API系列13-----Jdk8时间类转换,LocalDateTime转Date等
3.用C语言怎么编写万年历
Dubbo调用超时那些事儿
其实之前很早就看过Dubbo源码中关于超时这部分的处理逻辑,但是没有记录下来,最近在某脉上看到有人问了这个问题,想着再回顾一下。开始从dubbo的fpgagzip源码请求开始,看看dubbo(2.6.6)在超时这块是怎么处理的:
com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int)@Overridepublic ResponseFuture request(Object request, int timeout) throws RemotingException { if (closed) { throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");}// create request.Request req = new Request();req.setVersion(Version.getProtocolVersion());req.setTwoWay(true);req.setData(request);DefaultFuture future = new DefaultFuture(channel, req, timeout);try { channel.send(req);} catch (RemotingException e) { future.cancel();throw e;}return future;}DefaultFuture从返回值ResponseFuture类型可以看出,这是一个异步方法(不等同于Dubbo的异步调用)。那么调用超时的关键可以从ResponseFuture来看:
public interface ResponseFuture { Object get() throws RemotingException;Object get(int timeoutInMillis) throws RemotingException;void setCallback(ResponseCallback callback);boolean isDone();}可以看到这是一个接口,从request方法可以得知实现类是DefaultFuture,从构造函数入手:
public DefaultFuture(Channel channel, Request request, int timeout) { this.channel = channel;this.request = request;this.id = request.getId();this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);// put into waiting map.FUTURES.put(id, this);CHANNELS.put(id, channel);}可以得知每一个DefaultFuture都有一个id,并且等于requestId,timeout是从url中获取的配置,没有时默认ms。
从代码的注释可以看到FUTURES这个map应该就是关键,是一个waiting map。
DefaultFuture中还有一个方法:
public static void received(Channel channel, Response response) { try { DefaultFuture future = FUTURES.remove(response.getId());if (future != null) { future.doReceived(response);} else { logger.warn("The timeout response finally returned at "+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))+ ", response " + response+ (channel == null ? "" : ", channel: " + channel.getLocalAddress()+ " -> " + channel.getRemoteAddress()));}} finally { CHANNELS.remove(response.getId());}}可以看到调用的地方为:
com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received
@Overridepublic void received(Channel channel, Object message) throws RemotingException { //省略一些代码} else if (message instanceof Response) { handleResponse(channel, (Response) message);//省略一些代码}}com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse
static void handleResponse(Channel channel, Response response) throws RemotingException { if (response != null && !response.isHeartbeat()) { DefaultFuture.received(channel, response);}}回到DefaultFuture.received,可以看到通过Response id从FUTURES中拿了一个DefaultFuture出来,然后调用了doReceived方法,layui导航源码下载也就是说Response id和Request id 相同。结下来看看doReceived做了什么:
private void doReceived(Response res) { lock.lock();try { response = res;if (done != null) { done.signal();}} finally { lock.unlock();}if (callback != null) { invokeCallback(callback);}}首先是加锁,然后通过唤醒了阻塞在Condition上的线程。看看什么地方会阻塞在done这个条件上:
@Overridepublic Object get(int timeout) throws RemotingException { if (timeout <= 0) { timeout = Constants.DEFAULT_TIMEOUT;}if (!isDone()) { long start = System.currentTimeMillis();lock.lock();try { while (!isDone()) { done.await(timeout, TimeUnit.MILLISECONDS);if (isDone() || System.currentTimeMillis() - start > timeout) { break;}}} catch (InterruptedException e) { throw new RuntimeException(e);} finally { lock.unlock();}if (!isDone()) { throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));}}return returnFromResponse();}是get方法,get方法确实在request请求后被调用:
(Result) currentClient.request(inv, timeout).get()可以看到get方法的大致逻辑为,先获取锁,然后循环判断isDone,并阻塞等到条件,当条件超时,特征检测fast源码如果任务完成,或者超过timeout结束循环,接着判断isDone,如果超时抛出TimeoutException。并且通过sent(request请求时间)是否>0()来判断是clientSide还是serverSide超时。
isDone逻辑如下:
@Overridepublic boolean isDone() { return response != null;}如果是正常Response,也有可能是超时的现象,可以看到get方法最后调用了一个函数:
public interface ResponseFuture { Object get() throws RemotingException;Object get(int timeoutInMillis) throws RemotingException;void setCallback(ResponseCallback callback);boolean isDone();}0TIMEOUT SIDESERVER_TIMEOUT(服务端超时): 这个就是正常的我们消费端请求一个RPC接口,服务端由于性能等一些原因处理时间超过了timeout配置时间。如何去源码广告
CLIENT_TIMEOUT:我们可以看到是通过sent(上面有说sent>0)这个来判断是否clientTimeout,那么这个sent什么时候改变呢?就在发送请求的地方:
public interface ResponseFuture { Object get() throws RemotingException;Object get(int timeoutInMillis) throws RemotingException;void setCallback(ResponseCallback callback);boolean isDone();}1也就是说handler.sent一旦调用成功返回,那么就不算clientSide Timeout了。那么CLIENT_TIMEOUT大概率就是由于client端网络,系统等原因超时。
原文:/post/Java日期时间API系列-----Jdk8时间类转换,LocalDateTime转Date等
在Jdk8的Java.time包中,新日期时间API的灵活性和易用性得到了显著提升,尽管Date类型仍然广泛使用,负数源码转化补码但转换操作必不可少。本文将详细介绍LocalDateTime与Date,以及与其他时间类如Instant、LocalDate、LocalTime和ZonedDateTime之间的转换。以下是一个实用的工具类,供参考:
1. LocalDateTime到Date的转换
2. LocalDate到Date的转换
3. LocalTime到Date的转换
4. Instant到Date的转换,以及epochMilli毫秒到Date的转换
5. ZonedDateTime到Date的转换
6. 从Date反向转换至LocalDateTime
7. LocalDate到LocalDateTime的转换
8. LocalTime到LocalDateTime的转换
9. Instant到LocalDateTime的转换,以及epochMilli毫秒到LocalDateTime的转换
. Temporal到LocalDateTime的转换
. ZonedDateTime到LocalDateTime的转换
同样,Date到其他时间类的转换也包括:
- Date到LocalDate
- LocalDateTime到LocalDate
- Instant到LocalDate
- Temporal到LocalDate
- ZonedDateTime到LocalDate
- Date到LocalTime
- LocalDateTime到LocalTime
- Instant到LocalTime
- Temporal到LocalTime
- ZonedDateTime到LocalTime
- Date到Instant
- LocalDateTime到Instant
- LocalDate到Instant
- LocalTime到Instant
- epochMilli毫秒到Instant
- Temporal到Instant
- ZonedDateTime到Instant
要查看详细的测试代码和源码,请查看相关链接。
以上就是关于Java日期时间API中LocalDateTime与Date转换以及其他时间类之间转换的全面指南。
用C语言怎么编写万年历
1、首先下载安装Notepad++,这是一款免费的且能够编辑C语言的软件。2、然后下载安装tdm-gcc,这是为了给电脑配置环境变量,以便能够编译C语言的。
3、在安装完以上两款软件后,还要配置一下环境变量。
4、然后开始编辑C语言万年历,首先要判断一个年份是闰年还是平年,用一个子程序来做:
5、然后就开始写主程序:首先用scanf得到一个年份,在判断这个年份是平年还是闰年后用printf在CMD中打出来。
6、在编写完成后,在Notepad++界面下按下F5,在输入框中输入:
cmd /k gcc -o "$(CURRENT_DIRECTORY)\$(NAME_PART).exe" "$(FULL_CURRENT_PATH)" && CLS && "$(CURRENT_DIRECTORY)\$(NAME_PART).exe" & PAUSE & EXIT
7、最后点击运行,会弹出CMD,在里面输入年份后回车:例如输入,然后回车,就会生成年的万年历了!