外卖小程序09

目录

  • java中的四种引用
  • 垃圾回收机制
    • 介绍
    • 垃圾判断
      • 引用计数法
      • 可达性分析法
    • 垃圾收集算法
      • Mark-Sweep(标记-清除算法)
      • Coping算法
      • Mark-Compact算法
      • Generational-Collection算法
  • SpringTask
    • 介绍
    • Cron表达式
    • 使用步骤
      • 入门案例
    • 需求
      • 代码实现
        • 自定义任务类OrderTask
        • OrderMapper
  • WebSocket
    • 介绍
    • 对比HTTP
    • 使用步骤
    • 需求
    • 代码实现
      • Controller层
        • OrderController
      • Service层
        • OrderService
        • OrderServiceImpl
        • OrderMapper

java中的四种引用

直接上代码

package com.shifan.reference;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.io.IOException;
import java.lang.ref.*;

public class ReferenceTest2 {

    /**
     * 垃圾回收会调用此方法,如果打印了finalize,说明对象被回收了
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize");
    }

    /**
     * 强引用测试
     * 我们在创建对象时默认使用的引用就是强引用
     */
    @Test
    public void testNormalReference() throws IOException {
        //r是强引用,被强引用指向的对象是不会被回收的
        ReferenceTest2 r = new ReferenceTest2();
        //断开指向,对象将会被回收
        r = null;
        //显式调用垃圾回收
        System.gc();
        //阻塞当前线程,避免线程结束
        System.in.read();
    }

    /**
     * 测试软引用
     * 一般用于做缓存
     * 软引用类SoftReference继承自Reference类
     * 拥有两个构造方法
     * public SoftReference(T referent);
     * public SoftReference(T referent, ReferenceQueue q);
     * 第一个参数为软引用的对象,第二个参数为封装的待回收的对象
     */
    @Test
    public void testSoftReference(){
        A a = new A();
        //sr是一个软引用,只有当内存不足时,软引用指向的对象才会被回收
        SoftReference<A> sr = new SoftReference<A>(a);
        System.out.println(sr.get());//com.shifan.reference.ReferenceTest2$A@a74868d
        System.gc();
        System.out.println(sr.get());//com.shifan.reference.ReferenceTest2$A@a74868d
    }

    @NoArgsConstructor
    @AllArgsConstructor
    class A{
        String name;
    }
    /**
     * 测试弱引用
     * 一般用于做容器
     * 弱引用只要遇到垃圾回收其引用的对象就会被回收
     * 弱引用所指向的对象若被强引用所引用,遇到垃圾回收时依然会被回收
     * 弱引用也继承自Reference类,同样拥有两个构造方法,与软引用类似
     */
    @Test
    public void testWeakReference(){
        WeakReference<A> wr = new WeakReference(new A());
        System.out.println(wr.get());//com.shifan.reference.ReferenceTest2$A@12c8a2c0
        System.gc();
        System.out.println(wr.get());//null
    }

    /**
     * 测试虚引用
     * 虚引用与软引用,弱引用不同之处在于,虚引用只有一个构造方法,其中引入对象和引用队列都是必须传递的
     * 虚引用的作用是跟踪垃圾收集器手机对象的过程,gc过程中如果遇到了phantomReference,会将该引用存入
     * ReferenceQueue中让程序员自己处理,当我们调用了ReferenceQueue的poll方法移除了里面的引用之后
     * 被引用的对象就会变成inactive状态,即可回收状态
     */
    @Test
    public void testPhantom(){
        ReferenceQueue<A> rq = new ReferenceQueue<>();
        A a = new A();
        PhantomReference<A> pr = new PhantomReference<>(a, rq);
        a = null;
        System.out.println(pr.get());//null,由于虚引用指向的都是需要被回收的对象,所以此处的get方法一直是返回null
        System.gc();
        Reference<A> poll = (Reference<A>) rq.poll();
        System.out.println(poll);//java.lang.ref.PhantomReference@a74868d,有时为null,有时有地址
    }
}

垃圾回收机制

介绍

GC(garbage collection,内存自动回收):垃圾回收机制可以有效地防止内存泄漏

在java中,内存管理实际上是对对象的管理,gc通过有向图的方式,跟踪对象正在使用的对象

垃圾判断

引用计数法

通过对象被引用的数量判断对象是否应该被回收,若没有一个引用指向对象,则应该将该对象回收

缺点:无法解决循环引用的问题

可达性分析法

基本思路是以GC Roots的活跃引用为起始点开始搜索,如果没有一条路径可以到达一个对象,则称该对象是不可达的,亦可回收的.

垃圾收集算法

Mark-Sweep(标记-清除算法)

统一标记待回收的对象,然后清理

缺点:会生成很多内存碎片,可能会造成申请较大块内存空间时无法申请成功的情况

Coping算法

将内存划分为两块同样大小的空间,每次使用其中一块,并在垃圾回收时将存活的对象复制到另一片内存中去,然后清理这片内存

缺点:每次只能使用一半的空间,如果存活的对象非常多,复制的代价很大

Mark-Compact算法

标记阶段和Mark-Sweep算法一致,清理阶段此算法将存活的对象集中移动到内存的一端,然后清理存活对象边界外的区域

Generational-Collection算法

核心思想是将内存根据生命周期划分为若干部分,一般分为两部分,一部分用于存放新生代对象,新生代对象具有生命周期相对较短,每次需要回收的数量大的特点,另一部分存放老年代对象,老年代对象具有生命周期长的特点,每次需要回收的对象很少

**新生代算法:**新生代对象一般使用Coping算法,但并非将内存划分为同样大小的两片空间,而是将内存划分为较大的一块空间Eden和两块较小的空间Survivor,每次使用Eden空间和一块Survivor空间,回收对象前将存活的对象复制到未使用的Sruvivor空间中去,然后清理Eden和使用过的Survivor空间

**老年代算法:**老年代对象使用Mark-Compact算法实现对象的回收

SpringTask

介绍

Spring框架提供的任务调度工具,可以按照约定的时间自动执行某段代码逻辑

Cron表达式

本质就是一个字符串,通过cron表达式可以定义任务触发的时间

与SpringTask框架组合使用即可实现任务调度

**构成:**由6或7个域构成,空格隔开,每个域代表不同的含义,分别为秒,分,时,日,月,周,年(可选)

eg:2023年4月13日晚上21点整表示为:0 0 21 13 4 ? 2023

一般日和周不同时设置,设置其中一个,另一个用?表示

cron表达式在线生成器:https://cron.qqe2.com/

通配符:

* 表示所有值;

? 表示未说明的值,即不关心它为何值;

- 表示一个指定的范围;

, 表示附加一个可能值;

/ 符号前表示开始时间,符号后表示每次递增的值;

cron表达式案例:

*/5 * * * * ? 每隔5秒执行一次

0 */1 * * * ? 每隔1分钟执行一次

0 0 5-15 * * ? 每天5-15点整点触发

0 0/3 * * * ? 每三分钟触发一次

0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发

0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发

0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时

0 0 10,14,16 * * ? 每天上午10点,下午2点,4点

使用步骤

1.导入SpringTaskMaven坐标(包含于Spring-Context内)

2.在启动类上添加@EnableScheduling注解开启任务调度功能

3.自定义任务调度类

入门案例

在启动类上添加@EnableScheduling注解,编写自定义任务类,运行测试即可

/**
 * 自定义定时任务类
 */
@Component
@Slf4j
public class MyTask {

    /**
     * 定时任务 每隔5秒触发一次
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void executeTask(){
        log.info("定时任务开始执行:{}",new Date());
    }
}

需求

定时处理订单状态

1.每分钟触发一次待支付订单处理逻辑,将支付超时的订单状态置为已取消

2.每天凌晨一点触发一次派送中订单处理逻辑,将派送超过一小时的订单状态设为已完成

代码实现

自定义任务类OrderTask

/**
 * 定时任务类,定时处理订单状态
 */
@Component
@Slf4j
public class OrderTask {

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 处理支付超时订单
     */
    @Scheduled(cron = "0 * * * * ?")//每分钟触发一次
    public void processTimeoutOrder() {
        log.info("处理支付超时订单:{}", new Date());
        LocalDateTime orderTime = LocalDateTime.now().minusMinutes(15);
        //根据订单状态和下单时间查找订单
        List<Orders> ordersList = orderMapper.selectByStatusAndOrderTime(Orders.PENDING_PAYMENT, orderTime);
        if (ordersList != null && ordersList.size() > 0) {
            //更新订单状态
            ordersList.forEach(orders -> {
                orders.setStatus(Orders.CANCELLED);
                orders.setCancelReason("支付超时,自动取消");
                orders.setCancelTime(LocalDateTime.now());
                orderMapper.update(orders);
            });
        }
    }

    /**
     * 处理“派送中”状态的订单
     */
    @Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点触发一次
    public void processDeliveryOrder() {
        log.info("处理派送中订单:{}", new Date());
        LocalDateTime orderTime = LocalDateTime.now().minusHours(1);
        //根据订单状态和下单时间查找订单
        List<Orders> ordersList = orderMapper.selectByStatusAndOrderTime(Orders.DELIVERY_IN_PROGRESS, orderTime);
        if (ordersList != null && ordersList.size() > 0) {
            //更新订单状态
            ordersList.forEach(orders -> {
                orders.setStatus(Orders.COMPLETED);
                orderMapper.update(orders);
            });
        }
    }
}

OrderMapper

	/**
     * 根据状态和下单时间查询订单
     * @param status
     * @param orderTime
     */
    @Select("select * from orders where status = #{status} and order_time < #{orderTime}")
    List<Orders> getByStatusAndOrdertimeLT(Integer status, LocalDateTime orderTime);

WebSocket

介绍

基于TCP的新型网络协议,实现了浏览器和服务器全双工通信----只需进行一次握手即可建立持久性的连接,并进行双向数据传输.

对比HTTP

HTTP是短连接,WebSocket是长连接

HTTP是单向通信,基于请求响应,WebSocket是双向通信

HTTP和WebSocket都是基于TCP协议实现的

**缺点:**服务器长时间维护长连接成本较大,且各浏览器的支持程度不同,长连接受网络影响较大,需要处理好重连,所以WebSocket只适合在特定场景下使用

使用步骤

1.导入WebSocketMaven坐标

2.编写WebSocketServer服务端组件,用于和客户端通信

3.编写WebSocketConfiguration配置类,注册WebSocket服务端组件

4.编写定时任务类

需求

用户催单,用户催单后通知商家处理

通过WebSocket实现管理端页面和服务端保持长连接状态

当用户点击催单按钮后,调用WebSocket的相关API实现服务端向客户端推送消息

客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content

type 为消息类型,1为来单提醒 2为客户催单

orderId 为订单id

content 为消息内容

代码实现

Controller层

OrderController

@RestController("userOrderController")
@RequestMapping("user/order")
@Api(tags = "用户端订单相关接口")
@Slf4j
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 用户催单
     *
     * @param id
     * @return
     */
    @GetMapping("reminder/{id}")
    @ApiOperation("用户催单")
    public Result reminder(@PathVariable Long id) {
        log.info("用户催单:{}", id);
        orderService.reminder(id);
        return Result.success();
    }
}

Service层

OrderService

    /**
     * 用户催单
     *
     * @param id
     */
    void reminder(Long id);

OrderServiceImpl

    /**
     * 用户催单
     *
     * @param id
     */
    @Override
    public void reminder(Long id) {
        //查询订单
        Orders orders = orderMapper.selectByOrderId(id);
        //判断订单是否存在
        if (orders == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        //基于WebSocket实现催单
        HashMap hashMap = new HashMap();
        hashMap.put("type", 2);
        hashMap.put("orderId", id);
        hashMap.put("content", "订单号" + orders.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(hashMap));
    }

OrderMapper

	/**
     * 根据id查询订单
     * @param id
     */
    @Select("select * from orders where id=#{id}")
    Orders getById(Long id);

你可能感兴趣的:(Java,小程序,java)