JAVA多线程-线程池-实例模拟上厕所问题(三)
发表于(2012-11-10 01:06) from http://my.oschina.net/xpbug/blog/88259
为什么要使用线程池?
启动一个线程是一件很耗资源的事情, 启动线程需要跟底层操作系统打交道,为新线程开辟一个资源空间. 此外,一个进程中,线程过多,会耗尽资源,导致系统崩溃. 所以,重用和控制线程数量,是线程的必要知识.
Executors
J2ME中的java.util.concurrent.Executors就是一个线程执行器工厂,这个执行器可以管理线程池. Executors应该算是一个工厂,使用它类似newInstance的方法,可以创造出各种功能的ExecutorService(interface)实例. ExecutorService是Executor的继承接口.它的实例也就是线程执行器.
下面来看看Executors能产生什么功能的Executor实例.
newFixedThreadPool() - 创造一个管理固定数量线程的线程池.
newCachedThreadPool() - 创造一个管理非固定数量的线程池,线程一旦结束一段时间,则销毁.
newSingleThreadExecutor() - 产生一个单线程的执行器.
newSingleScheduledThreadExecutor() - 产生一个scheduled单线程执行器.
newScheduledThreadPool() - 创造一个scheduled线程的线程池.
有了Executor或者ExecutorService以后,怎么调用线程呢?
用例
一个厕所有3个坑,人们不停的进厕所做enen的事情.排量随机,蹲坑时间随机. 厕所的容量(capacity)为100, 当厕所的排量(volume)超过容量的时候, 通知清洁工来清洁. 清洁过程中不能再放新人进来. 厕所每天只服务100个人,然后停业.
本例中有4个类:
ThreadPool - main函数入口类.
Toilet - 厕所, 它使用一个具有3个线程处理能力的线程池来表达3个坑(holes)的概念.
People - 人, 排队上厕所
Cleaner - 清洁工, 清扫厕所
001 | package concurrency; |
002 |
003 | import java.util.Random; |
004 | import java.util.concurrent.ExecutorService; |
005 | import java.util.concurrent.Executors; |
006 |
007 | public class ThreadPoolTest { |
008 | |
009 | public static void main(String[] args) { |
010 | new ThreadPoolTest().test(); |
011 | } |
012 | |
013 | private void test() { |
014 | Toilet toilet = new Toilet(); |
015 | |
016 | boolean allowed = true ; |
017 | for ( int i= 0 ; allowed; i++) { |
018 | People p = new People(i+ "" , toilet); |
019 | allowed = toilet.allowIn(p); |
020 | } |
021 | } |
022 | |
023 | private class Toilet { |
024 | private volatile boolean cleaning = false ; |
025 | private volatile int volume= 0 ; |
026 | private final int CAPACITY = 100 ; |
027 | private volatile int peopleIn = 0 ; |
028 | private volatile int count = 0 ; |
029 | private Cleaner cleaner; |
030 | // 3 holes in his toilet. |
031 | private ExecutorService holes = Executors.newFixedThreadPool( 3 ); |
032 | |
033 | private Toilet() { |
034 | this .cleaner = new Cleaner( this ); |
035 | } |
036 | private synchronized boolean allowIn(Runnable people) { |
037 | // If toilet is cleaning or 3 holes are taken, wait. |
038 | while ( this .cleaning == true || this .peopleIn >= 3 ) { |
039 | try { |
040 | this .wait(); |
041 | } catch (InterruptedException e) { |
042 | e.printStackTrace(); |
043 | } |
044 | } |
045 | |
046 | // Only serves 100 people one day. |
047 | if (count > 100 ) { |
048 | this .holes.shutdown(); |
049 | return false ; |
050 | } else { |
051 | this .peopleIn(((People)people).name); |
052 | holes.submit(people); |
053 | return true ; |
054 | } |
055 | } |
056 | |
057 | private synchronized void enEn(String name, int v) { |
058 | this .volume += v; |
059 | System.out.println( "People[" +name+ "] put in [" +v+ "]. Toilet volume increases to [" +volume+ "]" ); |
060 | |
061 | // If the volume exceeds capacity, notify cleaner to clean. |
062 | if ( this .volume > this .CAPACITY) { |
063 | this .notifyCleaner(); |
064 | } |
065 | } |
066 |
067 | private void notifyCleaner() { |
068 | if ( this .cleaning == false ) { |
069 | System.out.println( "Toilet volume full with [" +volume+ "]. Notify cleaner." ); |
070 | holes.submit(cleaner); |
071 | } |
072 | } |
073 | |
074 | private synchronized void peopleIn(String name) { |
075 | System.out.println( "People[" +name+ "] comes in." ); |
076 | this .peopleIn ++; |
077 | this .count++; |
078 | } |
079 | |
080 | private synchronized void peopleOut(String name) { |
081 | System.out.println( "People[" +name+ "] comes out." ); |
082 | this .peopleIn --; |
083 | this .notifyAll(); |
084 | } |
085 | public synchronized void cleaning() { |
086 | this .cleaning = true ; |
087 | |
088 | } |
089 | public synchronized void cleaned() { |
090 | this .cleaning = false ; |
091 | this .notifyAll(); |
092 | } |
093 | } |
094 | |
095 | // One toilet cleaner. |
096 | private class Cleaner implements Runnable { |
097 | private Toilet toilet; |
098 | private Cleaner(Toilet t) { |
099 | this .toilet = t; |
100 | } |
101 |
102 | @Override |
103 | public void run() { |
104 | toilet.cleaning(); |
105 | System.out.println( "Toilet Cleaning..." ); |
106 | try { |
107 | Thread.sleep( 2000 ); |
108 | } catch (InterruptedException e) { |
109 | e.printStackTrace(); |
110 | } |
111 | this .toilet.volume = 0 ; |
112 | System.out.println( "Toilet Clean done." ); |
113 | toilet.cleaning = false ; |
114 | toilet.cleaned(); |
115 | } |
116 | } |
117 | |
118 | private class People implements Runnable { |
119 | private Toilet toilet; |
120 | private String name; |
121 | private People(String name, Toilet t) { |
122 | this .toilet = t; |
123 | this .name = name; |
124 | } |
125 |
126 | @Override |
127 | public void run() { |
128 | System.out.println( "People[" +name+ "] is en en en..." ); |
129 | try { |
130 | Thread.sleep( new Random().nextInt( 500 )); |
131 | } catch (InterruptedException e) { |
132 | e.printStackTrace(); |
133 | } |
134 | |
135 | toilet.enEn(name, new Random().nextInt( 11 )); |
136 | toilet.peopleOut(name); |
137 | } |
138 | |
139 | } |
140 |
141 | } |