【Java】滴答滴答—计时器工具

在多线程编程时,我们需要考虑到资源的有效利用和线程占有资源问题。

例如在C-S框架中,客户机连接服务器的操作。当客户机连接到服务器时,如果长时间没有进行信息交互而一直保持与服务器的连接,这不仅会增加服务器的负担,还会造成CPU资源的浪费。因此,我们完成一个计时器工具,检测当客户机在指定时间内有没有进行操作,如果没有则可以通过调用抽象方法doSomething()来对客户机或相关线程进行关闭或放在缓冲区中等操作,及时归还CPU资源;而当客户机需要进行信息交互时,重新向服务器发送连接请求。

在代码实现上必须要考虑锁和计时器的误差。

我们需要创建两个线程,第一个为本类Didadida下的线程,该线程用来在指定时间内唤醒doSomething()操作;第二个线程作为一个调用业务函数(在计时器时间之外)的线程,其通过内部类来实现,并且刚创建即阻塞,当第一个线程执行notify()时,唤醒该线程并执行doSomething()方法。

执行这两个线程时必须使用同一个对象锁,并且将线程的阻塞和唤醒作为临界资源避免其他线程抢占。

源代码:

package com.chy.timer.core;

public abstract class Didadida implements Runnable {
	private volatile boolean goon = false;
	private Object lock;
	private long delayTime;
	
	private static final long defaultTime = 1000;
	
	public Didadida() {
		this.lock = new Object();
	}
	
	public abstract void doSomething();
	
	public Didadida setDelayTime(long delayTime) {
		this.delayTime = delayTime;
		return this;
	}
	
	public void start() {
		if (goon == true) {
			return;
		}
		goon = true;
		
		new DidadidaWoker();
		new Thread(this, "Didadida").start();
	}
	
	@Override
	public void run() {
		if (delayTime == 0) {
			delayTime = defaultTime;
		}
		synchronized (lock) { 
			while (goon) {
				try {
					// 指定时间结束后唤醒阻塞线程;
					// 若业务函数所在线程没有在指定时间内完成业务并结束线程;
					// 则本线程的notify()为无效操作,进入下一时间片段。
					lock.wait(delayTime);
					lock.notify();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public class DidadidaWoker implements Runnable{
		
		public DidadidaWoker() {
			new Thread(this).start();
		}
		
		@Override
		public void run() {
			while (goon) {
				synchronized (lock) {
					try {
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				doSomething();
			}
		}
		
	}

}

你可能感兴趣的:(练习)