单例设计模式
单例设计模式
比较常见的有spring提供的ioc,控制翻转,只需要加一个componet注解,默认注解修饰的对象就是单例的
如果自己要实现一个单例,应该是如何一个思路呢
借鉴xxl-job里面客户端的代码
功能:一个线程后台起,每隔1天去扫描一下日志文件,只保留最近的30个日志文件的功能
代码样例
public class JobLogFileCleanThread {
private static Logger logger = LoggerFactory.getLogger(JobLogFileCleanThread.class);
private static JobLogFileCleanThread instance = new JobLogFileCleanThread();
public static JobLogFileCleanThread getInstance(){
return instance;
}
private Thread localThread;
private volatile boolean toStop = false;
public void start(final long logRetentionDays){
// limit min value
if (logRetentionDays < 3 ) {
return;
}
localThread = new Thread(new Runnable() {
@Override
public void run() {
while (!toStop) {
try {
// clean log dir, over logRetentionDays
File[] childDirs = new File(XxlJobFileAppender.getLogPath()).listFiles();
if (childDirs!=null && childDirs.length>0) {
// today
Calendar todayCal = Calendar.getInstance();
todayCal.set(Calendar.HOUR_OF_DAY,0);
todayCal.set(Calendar.MINUTE,0);
todayCal.set(Calendar.SECOND,0);
todayCal.set(Calendar.MILLISECOND,0);
Date todayDate = todayCal.getTime();
for (File childFile: childDirs) {
// valid
if (!childFile.isDirectory()) {
continue;
}
if (childFile.getName().indexOf("-") == -1) {
continue;
}
// file create date
Date logFileCreateDate = null;
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
logFileCreateDate = simpleDateFormat.parse(childFile.getName());
} catch (ParseException e) {
logger.error(e.getMessage(), e);
}
if (logFileCreateDate == null) {
continue;
}
if ((todayDate.getTime()-logFileCreateDate.getTime()) >= logRetentionDays * (24 * 60 * 60 * 1000) ) {
FileUtil.deleteRecursively(childFile);
}
}
}
} catch (Exception e) {
if (!toStop) {
logger.error(e.getMessage(), e);
}
}
try {
TimeUnit.DAYS.sleep(1);
} catch (InterruptedException e) {
if (!toStop) {
logger.error(e.getMessage(), e);
}
}
}
logger.info(">>>>>>>>>>> xxl-job, executor JobLogFileCleanThread thread destory.");
}
});
localThread.setDaemon(true);
localThread.setName("xxl-job, executor JobLogFileCleanThread");
localThread.start();
}
public void toStop() {
toStop = true;
if (localThread == null) {
return;
}
// interrupt and wait
localThread.interrupt();
try {
localThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
}
代码分析
- JobLogFileCleanThread 类就是一个单例模式,内部有一个静态变量instance,默认值是new JobLogFileCleanThread()自己本身
- 静态方法getInstance()取到的变量就是静态变量instance
- 为什么这个JobLogFileCleanThread的线程类自己本身没有继承Thread父类呢,而是里面又内嵌了一个Thread类型的localThread变量?
- JobLogFileCleanThread 自己有一个start方法,且是可以传递参数的,默认线程类Thread的start是不可以接受参数的,所以JobLogFileCleanThread类自己本身没有继承Thread类
- 可以看出start(long logRetentionDays)方法,内部起了一个new Thread的匿名内部类,并赋值给了变量localThread,匿名内部类里面写自己的业务逻辑,并且是个死循环,依赖一个flag标记,这个flag标记由voliate修饰,杜绝线程之间可见性问题也可以做到执行方法stop的时候,可以优雅关闭死循环的线程。
原创:做时间的朋友
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
2021-03-31 java异步转同步
2021-03-31 maven把依赖打进jar包