多线程计时器

在生活中,我们经常会定时执行某一项操作,这样就需要让线程暂停一段时间在继续运行,这篇文章就给大家介绍一下如何通过线程完成计时器。

第一种定时器:

try {
Thread.sleep(delayTime);
doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}

这种方案是最简单和最直接的,通过Thread.sleep()直接让线程休眠,但是在保证多线程安全的前提下,我们经常会用到锁,Thread.sleep()方法不会释放当前锁,就会使得在锁里运行Thread.sleep(),方法时,其他的线程会进入该锁的阻塞队列,造成了对CPU资源的浪费。因此这样的做法很不完善。

第二种定时器:

	
	@Override
	public void run() {
		while (goon) {
			synchronized (lock) {
				try {
					lock.wait(delayTime);
					doSomething();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

对于lock.wait(delayTime)这个定时器而言,由于它每次自动唤醒后都要继续做doSomething();的操作,以至于每次执行doSomething 的时间至少是等待的时间在加上doSomething操作本身需要的时间。定时不够准确。

第三种定时器:

@Override
	public void run() {
		while (goon) {
			// 这里才是真正的定时器,而且,它只定时!
			synchronized (lock) {
				try {
					lock.wait(delayTime);
					// 这里应该唤醒一个线程,这个线程专心负责执行Action!
					lock.notify();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	class TimeWorker implements Runnable {
		public TimeWorker() {
		}
		
		@Override
		public void run() {
			while (goon) {
				try {
					synchronized (lock) {
						lock.wait();
					}
					action.doSomething();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

这种方式是用线程配合来完成定时器的,我们用DidaDida这个类做专门的定时器,内部类TimeWorker专门处理doSomething。
假设TimeWork这个线程先开始工作,执行了lock.wait();方法后就自我阻塞了。定时线程获取锁之后进入工作状态后,执行lock.wait(delayTime);,等待delayTime毫秒之后,唤醒TimeWorker这个线程,定时线程继续循环,进入下一次延时。而另一边,TimeWork线程一旦或得了CPU资源后,就开始执行doSomething的操作,执行完毕之后,继续等待被唤醒,这样定时线程只专一的做一件事 —— 定时,而TimeWork只专心的处理doSomething。
即便是doSomething这个操作的时间非常长,在它执行一半的时候时间片段到了,定时线程再一次执行了lock.wait(delayTime);,这样也并不会影响定时器对时间的延迟
即便是几次优化其实还是有很多不精确的地方,比如TimeWork线程在被唤醒之后如果一直不能竞争上CPU资源,就无法执行,其等待的时间一样会比设置的时间长。

下面是DidaDida的完成类:

package com.mec.timer.didadida;

public class DidaDida implements Runnable {
	public static final long DEFAULT_DELAY_TIME = 1000;
	
	private long delayTime;
	private Object lock;
	private volatile boolean goon;
	
	private IDidaDidaAction action;
	
	public DidaDida() {
		this(DEFAULT_DELAY_TIME);
	}
	
	public DidaDida(long delayTime) {
		this(delayTime, null);
	}
	
	public DidaDida(long delayTime, IDidaDidaAction action) {
		this.lock = new Object();
		this.delayTime = delayTime;
		this.action = action;
	}

	public void setAction(IDidaDidaAction action) {
		this.action = action;
	}

	public void setDelayTime(long delayTime) {
		this.delayTime = delayTime;
	}

	public void start() {
		if (action == null) {
			System.out.println("无事可做!");
			return;
		}
		if (goon) {
			return;
		}
		goon = true;
		new Thread(new TimeWorker(), "TimeWork").start();
		new Thread(this, "DidaDida").start();
	}
	
	public void stop() {
		if (action == null) {
			System.out.println("没做任何事!");
			return;
		}
		if (goon == false) {
			System.out.println("时钟已经停止计时!");
			return;
		}
		goon = false;
	}
	
	@Override
	public void run() {
		while (goon) {
			// 这里才是真正的定时器,而且,它只定时!
			synchronized (lock) {
				try {
					lock.wait(delayTime);
					// 这里应该唤醒一个线程,这个线程专心负责执行Action!
					lock.notify();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	class TimeWorker implements Runnable {
		public TimeWorker() {
		}
		
		@Override
		public void run() {
			while (goon) {
				try {
					synchronized (lock) {
						lock.wait();
					}
					action.doSomething();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值