/* ****************************************************************************** * * Copyright 2008-2013 Hans Dijkema * * JRichTextEditor is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * JRichTextEditor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JRichTextEditor. If not, see <http://www.gnu.org/licenses/>. * * ******************************************************************************/ package nl.dykema.jxmlnote.utils; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.swing.SwingUtilities; /** * This class executes a runnable, but only if it is the last one * of a series. invokeLater() is called with a Runnable R. * This Runnable is wrapped in a wrapper Runnable, which monitors * the size of the series. This is executed on the AWT Event Queue/Thread. * If the series is of size 1, it will run its runnable otherwise, it * wil dispose of itself and doesn't run runnable. * * This class can be used to make events execute asynchonously, where * it is only important that the last one of a series of events is * eventually executed. * * NB. This can result in a starvation situation, where there runnables * keep being put on the AWT Queue, and the number of runnables queued * never reaches 1. * * @author Hans Dijkema * */ public class MakeAsync { private class SeriesRunnable implements Runnable { private Runnable R; public SeriesRunnable(Runnable r) { R=r; } public void run() { if (mustExecute()) { R.run(); } remove(R); } } Set<Runnable> series=new HashSet<Runnable>(); int timeout=1000; long lastExec=-1; private synchronized void add(Runnable r) { series.add(r); } private synchronized void remove(Runnable r) { series.remove(r); } private synchronized boolean mustExecute() { long time=System.currentTimeMillis(); if (series.size()==1) { lastExec=time; return true; } else if ((time-lastExec)>timeout) { lastExec=time; return true; } else { return false; } } public void invokeLater(Runnable r) { this.add(r); SwingUtilities.invokeLater(new SeriesRunnable(r)); } public MakeAsync(int starvationPreventionTimeout) { timeout=starvationPreventionTimeout; } }