ZOFTINO.COM android and web dev tutorials

Java DelayQueue Example

DelayQueue holds elements which can be taken after expiry of the specified delay. The elements to be added to the DelayQueue needs to implement Delayed interface. The first element in the DelayQueue whose delay time has expired becomes the head of the queue. In the queue, if there are no elements whose delay-time has expired, then there is no head. In this case poll returns null and take waits for an element to be available.

DelayQueue is a blocking and unbounded queue meaning it supports blocking add and remove operations when queue is full or empty respectively. It can’t contain null values. For other queue and blocking queue characteristics and examples, see Java Queue examples

DelayQueue Example

I’ll show how to use DelayQueue with an example. The example uses DelayQueue to start a chat window after user spends certain time on a web page. Time spent on a page and switch to the new page are simulated using random number of milliseconds as delay between page switches. The example contains delay class, delay object producer and consumer and manger class.

Delay object producer creates and posts a delay object to the delay queue each time there is a page change and delay object consumer processes the delay object and starts the chat.

Creating Delay Objects

The class whose instances are used as delay objects to be added to the DelayQueue needs to implement Delayed interface. Delayed interface defines getDelay() method which returns remaining delay time or zero or negative number to indicate that the delay has expired.

In the following example, delay class’s constructor takes start time and delay as arguments and the method getDelay checks if the specified delay has expired or not and returns appropriate value to indicate the expiry. The delay queue uses this method to determine whether a delay element is ready for consumption or not.

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class ChatTask implements Delayed{
	
	private int delayDuration;
	private long startTime;
	private int currentPage;
	
	public ChatTask(long startTime, int delayDuration, int currentPage) {
		this.startTime = startTime;
		this.delayDuration = delayDuration;
		this.currentPage = currentPage;
	}

	@Override
	public int compareTo(Delayed delayObj) {
		
		if(this.getDelay(null) > delayObj.getDelay(null)) {
			return 1;
		}
		return -1;
	}

	@Override
	public long getDelay(TimeUnit timeUnit) {
		if(System.currentTimeMillis() - startTime > delayDuration) {
			return 1;
		}else {
			return 0;
		}		   
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public int getDelayDuration() {
		return delayDuration;
	}

}

Delay Element Producer

Delay element producer instantiate delay object and add it to DelayQueue.

import java.util.concurrent.DelayQueue;

public class ChatTaskProducer {
	
	private DelayQueue<ChatTask> chatQueue;
	
	public ChatTaskProducer(DelayQueue<ChatTask> chatQueue) {
		this.chatQueue = chatQueue;
	}

	public void produceChatTask(int delay, int currentPage) {
		
		ChatTask ct = new ChatTask(System.currentTimeMillis(),
								delay, currentPage);
		
		chatQueue.add(ct);
		System.out.println("added new task, page "+currentPage
								+" delay "+delay);
	}
}

Delay Element Consumer

Consumer of delay element calls take() operation on the delay queue to obtain the expired delay element and process it.

import java.util.concurrent.DelayQueue;

public class ChatTaskConsumer {

	private DelayQueue<ChatTask> chatQueue;
	private int currentPage;
	
	public ChatTaskConsumer(DelayQueue<ChatTask> chatQueue) {
		this.chatQueue = chatQueue;
	}	

	public void startChatTaskConsumer() {	
		
		new Thread( new Runnable() {
			@Override
			public void run() {
				//take delayed tasks from the queue and process
				processChatTask();
			}			
		}).start();
	}
	public void processChatTask() {	
		try {
			while(currentPage < 15) {
				System.out.println("waiting for task");
				ChatTask ct = chatQueue.take();
				System.out.println("processing task page "+ct.getCurrentPage()
							+" delay "+ct.getDelayDuration());
				
				//if user is on the same after the delay start chat window
				if(ct.getCurrentPage() == currentPage) {
					initiateChat(ct );
				}		
			}
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void initiateChat(ChatTask ct ) {
		System.out.println("hello, here to help you on page "
									+ct.getCurrentPage());
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

}

Running DelayQueue Example

import java.util.Random;
import java.util.concurrent.DelayQueue;

public class ChatTaskManger {
	private int currentPage;

	public static void main(String[] args) {
		
		ChatTaskManger taskManger = new ChatTaskManger();
		taskManger.initiateChat();
	}
	
	public void initiateChat() {
		DelayQueue<ChatTask> chatQueue = new DelayQueue<ChatTask>();
		
		//start consumer
		ChatTaskConsumer consumer = new ChatTaskConsumer(chatQueue);
		consumer.startChatTaskConsumer();
		
		//instantiate producer
		ChatTaskProducer producer = new ChatTaskProducer(chatQueue);
		
		//limit number of elements being sent to queue
		while(currentPage < 15) {
			//simulate user clicking next page 
			//after spending some time on current page
			waitForPageChange();
			
			currentPage++;			
			System.out.println("user on page "+currentPage);
			
			//produce chat task delayed element and add it to queue
			producer.produceChatTask(getWaitTime(), currentPage);
			consumer.setCurrentPage(currentPage);
		}		
	}
	
	public void waitForPageChange() {        
        try {
			Thread.sleep(getWaitTime()*3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public int getWaitTime() {
		Random random = new Random();
        int rval = random.nextInt((10 - 1) + 1) + 1;
        return rval*100;
	}
}

Output:

waiting for task
user on page 1
added new task, page 1 delay 1000
processing task page 1 delay 1000
hello, here to help you on page 1
waiting for task
user on page 2
added new task, page 2 delay 500
processing task page 2 delay 500
hello, here to help you on page 2
waiting for task
user on page 3…