package com.gck;
import java.io.*;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Java Shutdown Hook的简单应用(kill -9 不会触发Shutdown hook函数)
* 运行时加载到内存的数据,在系统发生崩溃时,为了防止内存数据丢失,将内存中的数据序列化并保存到本地文件。
* 在下次启动程序时自动加载序列化文件。
*/
public class ShutdownHook {
/**
* 内部类,提供序列化测试
*/
private static class User implements Serializable{
int id; String name;
public User(int id, String name) { this.id = id; this.name = name; }
@Override
public String toString() { return "User{id=" + id + ", name='" + name + "'}"; }
}
// 链式队列
static LinkedBlockingQueue queue = new LinkedBlockingQueue();
// Java进程的shutdown钩子
private static void hook(){
Runtime.getRuntime().addShutdownHook(new Thread(()->{
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
System.out.println("开始执行ShutdownHook, 保存队列中的数据");
System.out.println("队列中的数据总数->" + queue.size());
File file = new File("D:/"+ new Date().getTime() +".queue");
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
User uu = null;
int index = 1;
while((uu = queue.poll()) != null) {
oos.writeObject(uu);
System.out.println("保存第"+(index++)+"个对象.");
}
oos.writeObject(null);//加入null 用来判断是否到末尾,如果不加会报错EOFException
System.out.println("保存队列中的数据完毕【"+file.getAbsolutePath()+"】");
} catch (Exception ex) {
System.out.println(ex.getMessage());
} finally {
try {
fos.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}));
}
public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException {
// 初始化shutdown hook
hook();
// 检查序列化文件
File file = new File("D:/1585817262570.queue");
if (file.exists()) {
// 发现序列化文件时,读取该文件并进行解析
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
User u =null;
while((u=(User)ois.readObject())!=null) {
System.out.println("保存的队列数据->" + u.toString());
queue.offer(u);
}
fis.close();
ois.close();
}
// 数据生产者
new Thread(() -> {
while (true) {
// 随机生成User对象
Random random = new Random();
int r = random.nextInt(200);
User u = new User(r,getRandomChar());
System.out.println("offer->" + u);
// 将User对象存储到队列中
try {
queue.put(u);
// 随机睡眠N秒
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// 数据消费者
new Thread(() -> {
while (true) {
try {
User u = queue.take();
System.out.println("take->" + u);
// 随机睡眠N秒
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 随机生成常见汉字
*/
public static String getRandomChar() {
String str = "";
int highCode,lowCode;
Random random = new Random();
highCode = (176 + Math.abs(random.nextInt(39))); //B0 + 0~39(16~55) 一级汉字所占区
lowCode = (161 + Math.abs(random.nextInt(93))); //A1 + 0~93 每区有94个汉字
byte[] b = new byte[2];
b[0] = (Integer.valueOf(highCode)).byteValue();
b[1] = (Integer.valueOf(lowCode)).byteValue();
try {
str = new String(b, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str;
}
}