PageRenderTime 28ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/util/WorkThreadPool.java

#
Java | 481 lines | 293 code | 61 blank | 127 comment | 71 complexity | c139e3cc4fe7d7cf989051a7749f483b MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * WorkThreadPool.java - Background thread pool that does stuff
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.util;
  23. //{{{ Imports
  24. import javax.swing.event.EventListenerList;
  25. import javax.swing.SwingUtilities;
  26. //}}}
  27. /**
  28. * A pool of work threads.
  29. * @author Slava Pestov
  30. * @version $Id: WorkThreadPool.java 5053 2004-05-29 01:55:26Z spestov $
  31. * @see org.gjt.sp.util.WorkThread
  32. * @since jEdit 2.6pre1
  33. */
  34. public class WorkThreadPool
  35. {
  36. //{{{ WorkThreadPool constructor
  37. /**
  38. * Creates a new work thread pool with the specified number of
  39. * work threads.
  40. * @param name The thread name prefix
  41. * @param count The number of work threads
  42. */
  43. public WorkThreadPool(String name, int count)
  44. {
  45. listenerList = new EventListenerList();
  46. if(count != 0)
  47. {
  48. threadGroup = new ThreadGroup(name);
  49. threads = new WorkThread[count];
  50. for(int i = 0; i < threads.length; i++)
  51. {
  52. threads[i] = new WorkThread(this,threadGroup,name + " #" + (i+1));
  53. }
  54. }
  55. else
  56. Log.log(Log.WARNING,this,"Async I/O disabled");
  57. } //}}}
  58. //{{{ start() method
  59. /**
  60. * Starts all the threads in this thread pool.
  61. */
  62. public void start()
  63. {
  64. /* not really needed since threads don't start until after */
  65. synchronized(lock)
  66. {
  67. started = true;
  68. if(awtRequestCount != 0 && requestCount == 0)
  69. queueAWTRunner();
  70. }
  71. if(threads != null)
  72. {
  73. for(int i = 0; i < threads.length; i++)
  74. {
  75. threads[i].start();
  76. }
  77. }
  78. } //}}}
  79. //{{{ addWorkRequest() method
  80. /**
  81. * Adds a work request to the queue.
  82. * @param run The runnable
  83. * @param inAWT If true, will be executed in AWT thread. Otherwise,
  84. * will be executed in work thread
  85. */
  86. public void addWorkRequest(Runnable run, boolean inAWT)
  87. {
  88. if(threads == null)
  89. {
  90. run.run();
  91. return;
  92. }
  93. synchronized(lock)
  94. {
  95. //{{{ if there are no requests, execute AWT requests immediately
  96. if(started && inAWT && requestCount == 0 && awtRequestCount == 0)
  97. {
  98. // Log.log(Log.DEBUG,this,"AWT immediate: " + run);
  99. if(SwingUtilities.isEventDispatchThread())
  100. run.run();
  101. else
  102. SwingUtilities.invokeLater(run);
  103. return;
  104. } //}}}
  105. Request request = new Request(run);
  106. //{{{ Add to AWT queue...
  107. if(inAWT)
  108. {
  109. if(firstAWTRequest == null && lastAWTRequest == null)
  110. firstAWTRequest = lastAWTRequest = request;
  111. else
  112. {
  113. lastAWTRequest.next = request;
  114. lastAWTRequest = request;
  115. }
  116. awtRequestCount++;
  117. // if no requests are running, requestDone()
  118. // will not be called, so we must queue the
  119. // AWT runner ourselves.
  120. if(started && requestCount == 0)
  121. queueAWTRunner();
  122. } //}}}
  123. //{{{ Add to work thread queue...
  124. else
  125. {
  126. if(firstRequest == null && lastRequest == null)
  127. firstRequest = lastRequest = request;
  128. else
  129. {
  130. lastRequest.next = request;
  131. lastRequest = request;
  132. }
  133. requestCount++;
  134. } //}}}
  135. lock.notifyAll();
  136. }
  137. } //}}}
  138. //{{{ waitForRequests() method
  139. /**
  140. * Waits until all requests are complete.
  141. */
  142. public void waitForRequests()
  143. {
  144. if(threads == null)
  145. return;
  146. synchronized(waitForAllLock)
  147. {
  148. while(requestCount != 0)
  149. {
  150. try
  151. {
  152. waitForAllLock.wait();
  153. }
  154. catch(InterruptedException ie)
  155. {
  156. Log.log(Log.ERROR,this,ie);
  157. }
  158. }
  159. }
  160. if(SwingUtilities.isEventDispatchThread())
  161. {
  162. // do any queued AWT runnables
  163. doAWTRequests();
  164. }
  165. else
  166. {
  167. try
  168. {
  169. SwingUtilities.invokeAndWait(new RunRequestsInAWTThread());
  170. }
  171. catch(Exception e)
  172. {
  173. Log.log(Log.ERROR,this,e);
  174. }
  175. }
  176. } //}}}
  177. //{{{ getRequestCount() method
  178. /**
  179. * Returns the number of pending requests.
  180. */
  181. public int getRequestCount()
  182. {
  183. return requestCount;
  184. } //}}}
  185. //{{{ getThreadCount() method
  186. /**
  187. * Returns the number of threads in this pool.
  188. */
  189. public int getThreadCount()
  190. {
  191. if(threads == null)
  192. return 0;
  193. else
  194. return threads.length;
  195. } //}}}
  196. //{{{ getThread() method
  197. /**
  198. * Returns the specified thread.
  199. * @param index The index of the thread
  200. */
  201. public WorkThread getThread(int index)
  202. {
  203. return threads[index];
  204. } //}}}
  205. //{{{ addProgressListener() method
  206. /**
  207. * Adds a progress listener to this thread pool.
  208. * @param listener The listener
  209. */
  210. public void addProgressListener(WorkThreadProgressListener listener)
  211. {
  212. listenerList.add(WorkThreadProgressListener.class,listener);
  213. } //}}}
  214. //{{{ removeProgressListener() method
  215. /**
  216. * Removes a progress listener from this thread pool.
  217. * @param listener The listener
  218. */
  219. public void removeProgressListener(WorkThreadProgressListener listener)
  220. {
  221. listenerList.remove(WorkThreadProgressListener.class,listener);
  222. } //}}}
  223. //{{{ Package-private members
  224. Object lock = new Object();
  225. Object waitForAllLock = new Object();
  226. //{{{ fireStatusChanged() method
  227. void fireStatusChanged(WorkThread thread)
  228. {
  229. final Object[] listeners = listenerList.getListenerList();
  230. if(listeners.length != 0)
  231. {
  232. int index = 0;
  233. for(int i = 0; i < threads.length; i++)
  234. {
  235. if(threads[i] == thread)
  236. {
  237. index = i;
  238. break;
  239. }
  240. }
  241. for(int i = listeners.length - 2; i >= 0; i--)
  242. {
  243. if(listeners[i] == WorkThreadProgressListener.class)
  244. {
  245. ((WorkThreadProgressListener)listeners[i+1])
  246. .statusUpdate(WorkThreadPool.this,index);
  247. }
  248. }
  249. }
  250. } //}}}
  251. //{{{ fireProgressChanged() method
  252. void fireProgressChanged(WorkThread thread)
  253. {
  254. final Object[] listeners = listenerList.getListenerList();
  255. if(listeners.length != 0)
  256. {
  257. int index = 0;
  258. for(int i = 0; i < threads.length; i++)
  259. {
  260. if(threads[i] == thread)
  261. {
  262. index = i;
  263. break;
  264. }
  265. }
  266. for(int i = listeners.length - 2; i >= 0; i--)
  267. {
  268. if(listeners[i] == WorkThreadProgressListener.class)
  269. {
  270. ((WorkThreadProgressListener)listeners[i+1])
  271. .progressUpdate(WorkThreadPool.this,index);
  272. }
  273. }
  274. }
  275. } //}}}
  276. //{{{ requestDone() method
  277. void requestDone()
  278. {
  279. synchronized(lock)
  280. {
  281. requestCount--;
  282. if(requestCount == 0 && firstAWTRequest != null)
  283. queueAWTRunner();
  284. }
  285. } //}}}
  286. //{{{ getNextRequest() method
  287. Request getNextRequest()
  288. {
  289. synchronized(lock)
  290. {
  291. Request request = firstRequest;
  292. if(request == null)
  293. return null;
  294. firstRequest = firstRequest.next;
  295. if(firstRequest == null)
  296. lastRequest = null;
  297. if(request.alreadyRun)
  298. throw new InternalError("AIEE!!! Request run twice!!! " + request.run);
  299. request.alreadyRun = true;
  300. /* StringBuffer buf = new StringBuffer("request queue is now: ");
  301. Request _request = request.next;
  302. while(_request != null)
  303. {
  304. buf.append(_request.id);
  305. if(_request.next != null)
  306. buf.append(",");
  307. _request = _request.next;
  308. }
  309. Log.log(Log.DEBUG,this,buf.toString()); */
  310. return request;
  311. }
  312. } //}}}
  313. //}}}
  314. //{{{ Private members
  315. //{{{ Instance variables
  316. private boolean started;
  317. private ThreadGroup threadGroup;
  318. private WorkThread[] threads;
  319. // Request queue
  320. private Request firstRequest;
  321. private Request lastRequest;
  322. private int requestCount;
  323. // AWT thread magic
  324. private boolean awtRunnerQueued;
  325. private Request firstAWTRequest;
  326. private Request lastAWTRequest;
  327. private int awtRequestCount;
  328. private EventListenerList listenerList;
  329. //}}}
  330. //{{{ doAWTRequests() method
  331. /** Must always be called with the lock held. */
  332. private void doAWTRequests()
  333. {
  334. while(requestCount == 0 && firstAWTRequest != null)
  335. {
  336. doAWTRequest(getNextAWTRequest());
  337. }
  338. } //}}}
  339. //{{{ doAWTRequest() method
  340. /** Must always be called with the lock held. */
  341. private void doAWTRequest(Request request)
  342. {
  343. // Log.log(Log.DEBUG,this,"Running in AWT thread: " + request);
  344. try
  345. {
  346. request.run.run();
  347. }
  348. catch(Throwable t)
  349. {
  350. Log.log(Log.ERROR,WorkThread.class,"Exception "
  351. + "in AWT thread:");
  352. Log.log(Log.ERROR,WorkThread.class,t);
  353. }
  354. awtRequestCount--;
  355. } //}}}
  356. //{{{ queueAWTRunner() method
  357. /** Must always be called with the lock held. */
  358. private void queueAWTRunner()
  359. {
  360. if(!awtRunnerQueued)
  361. {
  362. awtRunnerQueued = true;
  363. SwingUtilities.invokeLater(new RunRequestsInAWTThread());
  364. // Log.log(Log.DEBUG,this,"AWT runner queued");
  365. }
  366. } //}}}
  367. //{{{ getNextAWTRequest() method
  368. private Request getNextAWTRequest()
  369. {
  370. Request request = firstAWTRequest;
  371. firstAWTRequest = firstAWTRequest.next;
  372. if(firstAWTRequest == null)
  373. lastAWTRequest = null;
  374. if(request.alreadyRun)
  375. throw new InternalError("AIEE!!! Request run twice!!! " + request.run);
  376. request.alreadyRun = true;
  377. /* StringBuffer buf = new StringBuffer("AWT request queue is now: ");
  378. Request _request = request.next;
  379. while(_request != null)
  380. {
  381. buf.append(_request.id);
  382. if(_request.next != null)
  383. buf.append(",");
  384. _request = _request.next;
  385. }
  386. Log.log(Log.DEBUG,this,buf.toString()); */
  387. return request;
  388. } //}}}
  389. //}}}
  390. static int ID;
  391. //{{{ Request class
  392. static class Request
  393. {
  394. int id = ++ID;
  395. Runnable run;
  396. boolean alreadyRun;
  397. Request next;
  398. Request(Runnable run)
  399. {
  400. this.run = run;
  401. }
  402. public String toString()
  403. {
  404. return "[id=" + id + ",run=" + run + "]";
  405. }
  406. } //}}}
  407. //{{{ RunRequestsInAWTThread class
  408. class RunRequestsInAWTThread implements Runnable
  409. {
  410. public void run()
  411. {
  412. synchronized(lock)
  413. {
  414. awtRunnerQueued = false;
  415. if(requestCount == 0)
  416. doAWTRequests();
  417. }
  418. }
  419. } //}}}
  420. }