JAVA线程TimeUnit和定时任务创建的几种方式

一,TimeUnit的使用

主要作用:1. 时间颗粒度转换 2. 延时

1.时间颗粒度转换

TimeUnit是枚举实例,指定颗粒度单位

常用的颗粒度
		TimeUnit.DAYS;         //天  
		Calendar.HOUR_OF_DAY   //小时  是24小时制    
		Calendar.HOU 		   //小时  是12小时制
		TimeUnit.MINUTES       //分钟  
		TimeUnit.SECONDS       //秒  
		TimeUnit.MILLISECONDS  //毫秒 
		
转换:
System.out.println( TimeUnit.DAYS.toHours( 1 ) ); //将1天转化为小时
System.out.println( TimeUnit.HOURS.toSeconds( 1 ));//将1小时转化为秒,转换其他颗粒方法类似

2.延时

TimeUnit提供了可读性更好的线程暂停操作,通常用来替换Thread.sleep()。
记住TimeUnit.sleep()内部调用的Thread.sleep()也会抛出InterruptException。

TimeUnit写法:线程休眠4分钟

public static void main(String[] args) throws InterruptedException {
		TimeUnit.MINUTES.sleep(4);	
}

二,定时任务创建的几种方式

参考博客:Java并发学习之定时任务的几种玩法

不推荐使用 Thread.sleep的方式做定时任务
利用jdk实现定时任务,考虑Timer和ScheduledExecutorService
利用到了Spring,框架自带的定时任务

1.定时任务Timer和TimerTask方式

//TimerTask是一个抽象类,实现了Runnable接口,所以具备了多线程的能力。
TimerTask timerTask = new TimerTask() {
	@Override
	public void run() {
		System.out.println("timerTask 定时执行!");
	}
};

Timer timer = new Timer();
timer.schedule(timerTask, 5000);// 5秒后启动任务  
timer.schedule(timerTask, 5000, 3000);// 5秒后启动任务,以后每隔3秒执行一次线程   

Date date = new Date();
timer.schedule(timerTask, date, 3000);//以date为参数,指定某个时间点执行线程  

2.线程池方式实现(推荐使用)

// 获取线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

// 延迟3s后,执行定时任务
//		scheduledExecutorService.schedule(new Runnable() {
//			@Override
//			public void run() {
//				System.out.println("scheduledExecutorService 定时执行!");
//			}
//		}, 3, TimeUnit.SECONDS);

// 3s后,首次执行,然后每个3s执行一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
	@Override
	public void run() {
		System.out.println("scheduledExecutorService 定时执行!");
	}
}, 3, 3, TimeUnit.SECONDS);

3.线程池方式计算某个时间执行

public class Testb {

	static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
	static class Task extends TimerTask {
        @Override
        public void run() {
            System.out.println("进行校验");
            // 执行完毕,等待到6点发送报警
            int min = Calendar.getInstance().get(Calendar.MINUTE);
            int sec = Calendar.getInstance().get(Calendar.SECOND);
            long delayTime = TimeUnit.MINUTES.toSeconds(59 - min) + (60 - sec);
            executorService.schedule(new Runnable() {
				@Override
				public void run() {
					System.out.println("报警!");
				}
			}, delayTime, TimeUnit.SECONDS);
        }
    }
	public static void main(String[] args) throws InterruptedException {
		//假设每天凌晨5点数据导入完毕
		//在5:15分进行校验, 校验完成之后,45分钟后即六点将校验结果通知给owne
	 	Calendar calendar = Calendar.getInstance();// 15:20  40s
        // 计算sleep的小时数   先计算到5点整
        int sleepHour = 4 - calendar.get(Calendar.HOUR_OF_DAY);//4 - 15 = -11
        if (sleepHour < 0) {
			sleepHour = 24 + sleepHour;
		}
    	int minute = 59 - calendar.get(Calendar.MINUTE);//20
    	int second = 60 - calendar.get(Calendar.SECOND);//40s
        long delay = TimeUnit.HOURS.toSeconds(sleepHour) + TimeUnit.MINUTES.toSeconds(minute) + second;
        // 再加15分钟 延时到5:15
        delay += TimeUnit.MINUTES.toSeconds(15);
        executorService.scheduleAtFixedRate(new Task(), delay, TimeUnit.DAYS.toSeconds(1), TimeUnit.SECONDS);
	}
	
}

三,线程池的创建和自定义线程池

1.线程池的创建

//newFixedThreadPool()固定大小的线程池,阻塞队列使用LinkedBlockingQueue
//newSingleThreadExecutor()单个线程线程池,阻塞队列使用LinkedBlockingQueue
//newCachedThreadPool()缓存线程池,阻塞队列使用SynchronousQueue
//newScheduledThreadPool定时线程池,该线程池可用于周期性地去执行任务,通常用于周期性的同步数据。

//采用Executors创建定时线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

2.自定义线程池

参考博客:JAVA进阶----ThreadPoolExecutor机制

线程池的正确使用:
阿里编码规范:
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
  主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
  主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

//阻塞队列数
//ArrayBlockingQueue 数组结构组成的有界阻塞队列,此队列按照先进先出(FIFO)的原则
//LinkedBlockingQueue 一个由链表结构组成的无界阻塞队列,此队列按照先出先进的原则进行排序
//SynchronousQueue 不存储元素的阻塞队列

定制属于自己的阻塞线程池:

public class CustomThreadPoolExecutor {    
    /**
     * 自定义线程池
     */
    private ThreadPoolExecutor pool = null;    
        
    /**  
     * 
     * 线程池初始化方法    
     * corePoolSize 核心线程池大小----1  
     * maximumPoolSize 最大线程池大小----3  
     * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit  
     * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES  
     * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(5)====5容量的阻塞队列  
     * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂  
     * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,  
     *                          即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)),  
     *                          任务会交给RejectedExecutionHandler来处理  
     */    
    public void init() {    
        pool = new ThreadPoolExecutor(    
                1,    
                3,    
                30,    
                TimeUnit.MINUTES,    
                new ArrayBlockingQueue<Runnable>(5),    
                new CustomThreadFactory(),    
                new CustomRejectedExecutionHandler());    
    }    
    
    /**
     * 线程池销毁方法     
     */
    public void destory() {    
        if(pool != null) {    
            pool.shutdownNow();    
        }    
    }    
        
    /**
     * 获取自定义线程池     
     * @return
     */
    public ExecutorService getCustomThreadPoolExecutor() {    
        return this.pool;    
    }    
    
    /**
     * 
     * @Description: 定制的线程工厂
     * @author: lys
     */
    private class CustomThreadFactory implements ThreadFactory {  
    	//Atomic包下提供具有原子性类型:如
    	//AtomicBoolean :原子更新布尔类型。
    	//AtomicLong :原子更新长整型。
    	//AtomicInteger :原子更新整型。 
        private AtomicInteger count = new AtomicInteger(0);    
            
        @Override    
        public Thread newThread(Runnable r) {    
            Thread t = new Thread(r);    
            //addandget为先添加后获取,类似于++i
            String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);    
            System.out.println(threadName);    
            t.setName(threadName);    
            return t;    
        }    
    }    
        
    /**
     *   
     * @Description: 拒绝策略
     * @author: lys
     */
    private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {    
    
        @Override    
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {    
            try {  
                // 核心改造点,由blockingqueue的offer改成put阻塞方法  
            	// offer方法当队列满,而且放入时间超过设定时间时,返回false;
            	// put方法当队列满时,会调用wait方法,put方法会等待一个空的位置出来,然后再执行insert
                executor.getQueue().put(r);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }    
    }    
        
    // 测试构造的线程池    
    public static void main(String[] args) {    
          
        CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();    
        // 1.初始化    
        exec.init();    
        // 获取自定义线程池    
        ExecutorService pool = exec.getCustomThreadPoolExecutor();    
        for(int i=1; i<100; i++) {    
            System.out.println("提交第" + i + "个任务!");    
            // 在线程池里创建线程执行任务	 
            pool.execute(new Runnable() {    
                @Override    
                public void run() {    
                    try {    
                        System.out.println(">>>task is running=====");   
                        TimeUnit.SECONDS.sleep(10);  
                    } catch (InterruptedException e) {    
                        e.printStackTrace();    
                    }    
                }    
            });    
        }    
            
            
        // 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了    
        // exec.destory();    
            
        try {    
            Thread.sleep(10000);    
        } catch (InterruptedException e) {    
            e.printStackTrace();    
        }    
    }    
}   
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 1 使用java Timer类来实现:通过 Timer 和 TimerTask 来实现定时任务。2. 使用java Quartz来实现:Quartz 是一个完全由 Java 编写的开源定时任务框架。3. 使用Spring 框架的Task定时任务:Spring 框架自带的Task定时任务,可以利用这个特性来实现定时任务。4. 使用Java线程池来实现:可以使用Java线程池来实现定时任务,通过设置线程池线程的定时执行时间来实现定时任务。 ### 回答2: 以下是几种Java定时任务的实现案例: 1. 使用Timer类:Timer类可用于在指定的时间间隔内调度任务。可以创建一个Timer对象,并使用Timer.schedule()方法在指定的时间间隔内执行任务。 例如: ``` Timer timer = new Timer(); TimerTask task = new TimerTask() { public void run() { // 执行任务逻辑 } }; // 在延迟1000毫秒后,每隔2000毫秒执行一次任务 timer.schedule(task, 1000, 2000); ``` 2. 使用ScheduledExecutorService接口:ScheduledExecutorService是一个高度可用的并发定时任务执行器,可用于按指定的时间间隔执行任务。 例如: ``` ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Runnable task = new Runnable() { public void run() { // 执行任务逻辑 } }; // 在延迟1000毫秒后,每隔2000毫秒执行一次任务 executor.scheduleAtFixedRate(task, 1000, 2000, TimeUnit.MILLISECONDS); ``` 3. 使用Quartz框架:Quartz是一个功能强大的开源任务调度框架,可以用于执行复杂的定时任务。它提供了灵活的配置选项和强大的调度功能,支持持久性存储和集群部署。 例如: ```java // 创建触发器 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInMilliseconds(2000) .repeatForever()) .build(); // 创建任务 JobDetail job = JobBuilder.newJob(MyJob.class) .withIdentity("job1", "group1") .build(); // 创建调度器 Scheduler scheduler = new StdSchedulerFactory().getScheduler(); scheduler.start(); scheduler.scheduleJob(job, trigger); ``` 需要注意的是,以上这些只是Java定时任务的几个常见实现方式,还有其他方式,如使用Spring框架的任务调度功能、使用Quartz的注解方式等。根据项目的具体需求和场景,可以选择合适的定时任务实现方式。 ### 回答3: 以下是几种Java定时任务的实现案例: 1. 使用JavaTimer类:可以通过Timer类来实现简单的定时任务。可以创建一个Timer对象,并使用其schedule()方法来指定任务要运行的时间,并在指定的时间间隔内运行。例如,可以使用Timer类来创建一个每隔一分钟执行一次的任务。 2. 使用Java的ScheduledExecutorService接口:该接口是Java提供的一个更强大的定时任务执行框架。可以通过创建一个ScheduledExecutorService对象,并使用其schedule()或者scheduleAtFixedRate()方法来指定任务的运行时间和间隔。例如,可以使用ScheduledExecutorService来创建一个每隔一分钟执行一次的任务,并在任务执行后延迟一定的时间再次执行。 3. 使用Spring框架的@Scheduled注解:如果你的应用程序是基于Spring框架的,可以使用Spring的@Scheduled注解来实现定时任务。只需在你的任务方法上添加@Scheduled注解,并指定任务的执行时间间隔。Spring会自动创建一个定时任务调度器,定时执行你的任务。 4. 使用Quartz框架:Quartz是一个功能强大的开源任务调度框架,可以用于Java应用程序中的定时任务管理。Quartz提供了丰富的API来定义和调度任务,支持复杂的定时任务配置。使用Quartz,可以创建基于时间表达式的任务,并将其作为独立的模块集成到你的应用程序中。 这些只是一些常见的Java定时任务实现案例,具体实现取决于你的需求和应用程序的架构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值