最新java实现延时处理,mysql面试题sql语句

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

最新整理面试题
在这里插入图片描述

上述的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题

最新整理电子书

在这里插入图片描述

最新整理大厂面试文档

在这里插入图片描述

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

import io.netty.util.Timer;

import io.netty.util.TimerTask;

import java.util.concurrent.TimeUnit;

public class HashedWheelTimerTest {

static class MyTimerTask implements TimerTask{

boolean flag;

public MyTimerTask(boolean flag){

this.flag = flag;

}

public void run(Timeout timeout) throws Exception {

// TODO Auto-generated method stub

System.out.println(“要去数据库删除订单了。。。。”);

this.flag =false;

}

}

public static void main(String[] argv) {

MyTimerTask timerTask = new MyTimerTask(true);

Timer timer = new HashedWheelTimer();

timer.newTimeout(timerTask, 3, TimeUnit.SECONDS);//此处设置在时间轮第几个执行(本代码设置为第3格)

int i = 1;

while(timerTask.flag){

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(i+“秒过去了”);

i++;

}

}

}

测试结果如下:

在这里插入图片描述

3.3 优缺点


  • 优点:效率高,任务触发时间延迟时间比delayQueue低,代码复杂度比delayQueue低。

  • 缺点:

(1)服务器重启后,数据全部消失,怕宕机

(2)集群扩展相当麻烦

(3)因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现OOM异常

4.redis缓存

======================================================================

对于redis缓存的实现我们有两种方式:

  • 1.利用redis的zset,zset是一个有序集合,每一个元素(member)都关联了一个score,通过score排序来取集合中的值

  • 2.使用redis的Keyspace Notifications(键空间机制),就是利用该机制可以在key失效之后,提供一个回调,实际上是redis会给客户端发送一个消息。

4.1 利用redis的zset


添加元素:ZADD key score member [[score member] [score member] …]

按顺序查询元素:ZRANGE key start stop [WITHSCORES]

查询元素score:ZSCORE key member

移除元素:ZREM key member [member …]

下面我通过实操来给大家演示一下

添加单个元素

redis> ZADD page_rank 10 google.com

添加多个元素

redis> ZADD page_rank 9 baidu.com 8 bing.com

(integer) 2

在这里插入图片描述

按顺序查询元素 0 -1表示查询所有

ZRANGE page_rank 0 -1 WITHSCORES

在这里插入图片描述

查询元素的score值

redis> ZSCORE page_rank bing.com

在这里插入图片描述

移除单个元素

redis> ZREM page_rank google.com

在这里插入图片描述

在这里插入图片描述

我们具体将其和和我们要实现的功能联系在一起呢?

在这里插入图片描述

4.1.1 添加redis依赖

org.springframework.boot

spring-boot-starter-redis

1.4.7.RELEASE

具体的实现如下:

import java.util.Calendar;

import java.util.Set;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.Tuple;

public class AppTest {

private static final String ADDR = “192.168.1.2”;

private static final int PORT = 6379;

private static JedisPool jedisPool = new JedisPool(ADDR, PORT);

private static int waitTime = 10;//以10秒为基准

public static Jedis getJedis() {

return jedisPool.getResource();

}

//生产者,生成5个订单放进去

public void productionDelayMessage() {

long startTime = System.currentTimeMillis();

for (int i = 0; i < 5; i++) {

//延迟3秒

Calendar cal1 = Calendar.getInstance();

waitTime += 5;//每个订单之间的间隔为5秒

cal1.add(Calendar.SECOND, waitTime);

int second3later = (int) (cal1.getTimeInMillis() / 1000);

AppTest.getJedis().zadd(“OrderId”, second3later, “OID0000001” + i);

long endTime = System.currentTimeMillis();

System.out.println((endTime - startTime) / 1000 + “s:redis生成了一个订单任务:订单ID为” + “OID0000001” + i);

}

}

//消费者,取订单

public void consumerDelayMessage() {

Jedis jedis = AppTest.getJedis();

long startTime = System.currentTimeMillis();

while (true) {

Set items = jedis.zrangeWithScores(“OrderId”, 0, 1);

if (items == null || items.isEmpty()) {

System.out.println(“当前没有等待的任务”);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

continue;

}

int score = (int) ((Tuple) items.toArray()[0]).getScore();

Calendar cal = Calendar.getInstance();

int nowSecond = (int) (cal.getTimeInMillis() / 1000);

if (nowSecond >= score) {

String orderId = ((Tuple) items.toArray()[0]).getElement();

jedis.zrem(“OrderId”, orderId);

long endTime = System.currentTimeMillis();

System.out.println((endTime - startTime) / 1000 + “s:redis消费了一个任务:消费的订单OrderId为” + orderId);

}

}

}

public static void main(String[] args) {

AppTest appTest = new AppTest();

appTest.productionDelayMessage();//创建消费订单

appTest.consumerDelayMessage();//由消费者进行消费

}

}

测试结果如下:

在这里插入图片描述

通过上述结果我们可以看出每隔5秒消费了一笔订单

然而上面的实现却有一个致命的问题: 在高并发条件下,多消费者会取到同一个订单号

我们使用多线程进行测试一下

import java.util.concurrent.CountDownLatch;

public class ThreadTest {

private static final int threadNum = 10;//线程数

private static CountDownLatch cdl = new CountDownLatch(threadNum);

static class DelayMessage implements Runnable {

public void run() {

try {

cdl.await();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

AppTest appTest = new AppTest();

appTest.consumerDelayMessage();

}

}

public static void main(String[] args) {

AppTest appTest = new AppTest();

appTest.productionDelayMessage();

for (int i = 0; i < threadNum; i++) {

new Thread(new DelayMessage()).start();

cdl.countDown();

}

}

}

在这里插入图片描述

可以看出出现了多个线程消费同一个资源的情况,这种情况肯定是不允许的,所以给出两个解决方案让大家参考

  • 1.用分布式锁,但是用分布式锁,性能下降了

  • 2.对ZREM的返回值进行判断,只有大于0的时候,才消费数据

由于方案1涉及到java分布式锁的设计,后面我会专门出一期关于java分布式锁的内容讲解,同时也会将第一个方法的内容补全,下面我们先看看如何通过ZREM来进行解决多线程消费同一个订单的问题

4.1.2 解决多线程消费同一资源

我们将consumerDelayMessage()方法中的

在这里插入图片描述

改为以下内容

if (nowSecond >= score) {

String orderId = ((Tuple) items.toArray()[0]).getElement();

Long num = jedis.zrem(“OrderId”, orderId);

long endTime = System.currentTimeMillis();

if (num != null && num > 0) {

System.out.println((endTime - startTime) / 1000 + “s:redis消费了一个任务:消费的订单OrderId为” + orderId);

}

}

再次进行多线程的测试

在这里插入图片描述

4.2 使用redis的Keyspace Notifications(键空间机制)


在redis的配置文件中(redis.conf)中,加入以下配置

notify-keyspace-events Ex

具体操作代码如下:

package com.example.test.test;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPubSub;

public class RedisTest {

private static final String ADDR = “192.168.1.2”;

private static final int PORT = 6379;

private static JedisPool jedis = new JedisPool(ADDR, PORT);

private static RedisSub sub = new RedisSub();

public static void init() {

new Thread(new Runnable() {

public void run() {

jedis.getResource().subscribe(sub, “keyevent@0:expired”);

}

}).start();

}

public static void main(String[] args) throws InterruptedException {

init();

for (int i = 0; i < 10; i++) {

String orderId = “OID000000” + i;

jedis.getResource().setex(orderId, 3, orderId);

System.out.println(System.currentTimeMillis() + “ms:” + orderId + “订单生成”);

}

}

static class RedisSub extends JedisPubSub {

public void onMessage(String channel, String message) {

System.out.println(System.currentTimeMillis() + “ms:” + message + “订单取消”);

}

}

}

在这里插入图片描述

可以明显看到3秒过后,订单取消了

但是这种方法有个很大的弊端,redis的pub/sub机制存在一个硬伤,官网内容如下

Because Redis Pub/Sub is fire and forget currently there is no way to use this feature if your application demands reliable notification of events, that is, if your Pub/Sub client disconnects, and reconnects later, all the events delivered during the time the client was disconnected are lost.

我给大家翻译翻译什么意思

Redis的发布/订阅目前是即发即弃(fire and forget)模式的,因此无法实现事件的可靠通知。也就是说,如果发布/订阅的客户端断链之后又重连,则在客户端断链期间的所有事件都丢失了。因此,方案二不是太推荐。当然,如果你对可靠性要求不高,可以使用。

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

Java程序员秋招三面蚂蚁金服,我总结了所有面试题,也不过如此

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

BAWk5pbmVTdW4=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

可以明显看到3秒过后,订单取消了

但是这种方法有个很大的弊端,redis的pub/sub机制存在一个硬伤,官网内容如下

Because Redis Pub/Sub is fire and forget currently there is no way to use this feature if your application demands reliable notification of events, that is, if your Pub/Sub client disconnects, and reconnects later, all the events delivered during the time the client was disconnected are lost.

我给大家翻译翻译什么意思

Redis的发布/订阅目前是即发即弃(fire and forget)模式的,因此无法实现事件的可靠通知。也就是说,如果发布/订阅的客户端断链之后又重连,则在客户端断链期间的所有事件都丢失了。因此,方案二不是太推荐。当然,如果你对可靠性要求不高,可以使用。

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

[外链图片转存中…(img-ve2xXGcI-1715635634955)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值