随笔 - 8, 文章 - 0, 评论 - 6, 引用 - 0
数据加载中……

一个简化的java线程池示例

//以前写在blogger上的一篇老文了
曾经很好奇线程池是怎么实现的,.net中有现成的线程池可以使用,但是java中没有。还有就是Servlet的service方法是怎么样为每一个 Request在不同的线程中独立服务的,由于Servlet接口没有继承自Runnable接口,因此无法直接由一个Servlet对象生成多个线程。后来在网上找到了一个java版本的线程池的例子(http://www.informit.com/articles/article.asp?p= 30483&seqNum=1&rl=1)在该例子的基础上简化得到了下面这个版本的java线程池,记录在这里。
*******************
ThreadPool.java
*******************

package threadPool;

import java.util.ArrayList;
import java.util.Collection;

public class ThreadPool
{
    Thread[] threadArray;
    Collection
<Runnable> jobs = new ArrayList<Runnable>();
 
    
public ThreadPool(int threadNum)
    
{
        threadArray 
= new WorkerThread[threadNum];
        
for (Thread thread : threadArray)
        
{
            thread 
= new WorkerThread();
            thread.start();
        }

    }

 
    
public synchronized void addJob(Runnable job)
    
{
        jobs.add(job);
        notify();
    }

 
    
private synchronized Runnable getJob()
    
{
        
while(jobs.isEmpty())
        
{
            
try
            
{
                wait();
            }
 catch (InterruptedException e)
            
{
                e.printStackTrace();
            }

        }

        Runnable job 
=  jobs.iterator().next();
        jobs.remove(job);
        
return job;
    }

    
    
private class WorkerThread extends Thread
    
{
        
public void run()
        
{
            Runnable job 
= null;
            
while(job == null)
            
{
                job 
= getJob();
                
if(job != null)
                
{
                    job.run();
                }

                job 
= null;
            }

       }

    }

}


 

*******************
ThreadPoolTest.java
*******************

package threadPool;

public class ThreadTest
{
    
private static class PrintClass implements Runnable
    
{
        
private int threadNo;
  
        
public PrintClass(int threadNo)
        
{
            
this.threadNo = threadNo;
        }

        
        
public void run()
        
{
            
for(int i = 0; i < 10; i++)
            
{
                
synchronized (System.out)
                
{
                    System.out.println(
"Thread "+threadNo+""+i);
                }

                
try
                
{
                    Thread.sleep(
1000);
                }
 catch (InterruptedException e)
                
{
                    e.printStackTrace();
                }

            }

        }
 
    }

 
    
public static void main(String[] args)
    
{
        ThreadPool tp 
= new ThreadPool(3);
        
for(int i=0; i <10; i++)
        
{
            tp.addJob(
new PrintClass(i));
        }

        
synchronized (System.out)
        
{
            System.out.println(
"Job adding finished");
        }

    }

}

posted on 2007-05-15 12:53 Job Hu 阅读(886) 评论(3)  编辑  收藏

评论

# re: 一个简化的java线程池示例  回复  更多评论   

DB连接池示例:
 
  1/*
  2 * Copyright (c) 1998 by Gefion software.
  3 *
  4 * Permission to use, copy, and distribute this software for
  5 * NON-COMMERCIAL purposes and without fee is hereby granted
  6 * provided that this copyright notice appears in all copies.
  7 *
  8 */

  9
 10import java.io.*;
 11import java.sql.*;
 12import java.util.*;
 13import java.util.Date;
 14
 15/**
 16 * This class is a Singleton that provides access to one or many
 17 * connection pools defined in a Property file. A client gets
 18 * access to the single instance through the static getInstance()
 19 * method and can then check-out and check-in connections from a pool.
 20 * When the client shuts down it should call the release() method
 21 * to close all open connections and do other clean up.
 22 */

 23public class DBConnectionManager {
 24    static private DBConnectionManager instance;       // The single instance
 25    static private int clients;
 26
 27    private Vector drivers = new Vector();
 28    private PrintWriter log;
 29    private Hashtable pools = new Hashtable();
 30    
 31    /**
 32     * Returns the single instance, creating one if it's the
 33     * first time this method is called.
 34     *
 35     * @return DBConnectionManager The single instance.
 36     */

 37    static synchronized public DBConnectionManager getInstance() {
 38        if (instance == null{
 39            instance = new DBConnectionManager();
 40        }

 41        clients++;
 42        return instance;
 43    }

 44    
 45    /**
 46     * A private constructor since this is a Singleton
 47     */

 48    private DBConnectionManager() {
 49        init();
 50    }

 51    
 52    /**
 53     * Returns a connection to the named pool.
 54     *
 55     * @param name The pool name as defined in the properties file
 56     * @param con The Connection
 57     */

 58    public void freeConnection(String name, Connection con) {
 59        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
 60        if (pool != null{
 61            pool.freeConnection(con);
 62        }

 63    }

 64        
 65    /**
 66     * Returns an open connection. If no one is available, and the max
 67     * number of connections has not been reached, a new connection is
 68     * created.
 69     *
 70     * @param name The pool name as defined in the properties file
 71     * @return Connection The connection or null
 72     */

 73    public Connection getConnection(String name) {
 74        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
 75        if (pool != null{
 76            return pool.getConnection();
 77        }

 78        return null;
 79    }

 80    
 81    /**
 82     * Returns an open connection. If no one is available, and the max
 83     * number of connections has not been reached, a new connection is
 84     * created. If the max number has been reached, waits until one
 85     * is available or the specified time has elapsed.
 86     *
 87     * @param name The pool name as defined in the properties file
 88     * @param time The number of milliseconds to wait
 89     * @return Connection The connection or null
 90     */

 91    public Connection getConnection(String name, long time) {
 92        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
 93        if (pool != null{
 94            return pool.getConnection(time);
 95        }

 96        return null;
 97    }

 98    
 99    /**
100     * Closes all open connections and deregisters all drivers.
101     */

102    public synchronized void release() {
103        // Wait until called by the last client
104        if (--clients != 0{
105            return;
106        }

107        
108        Enumeration allPools = pools.elements();
109        while (allPools.hasMoreElements()) {
110            DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
111            pool.release();
112        }

113        Enumeration allDrivers = drivers.elements();
114        while (allDrivers.hasMoreElements()) {
115            Driver driver = (Driver) allDrivers.nextElement();
116            try {
117                DriverManager.deregisterDriver(driver);
118                log("Deregistered JDBC driver " + driver.getClass().getName());
119            }

120            catch (SQLException e) {
121                log(e, "Can't deregister JDBC driver: " + driver.getClass().getName());
122            }

123        }

124    }

125    
126    /**
127     * Creates instances of DBConnectionPool based on the properties.
128     * A DBConnectionPool can be defined with the following properties:
129     * <PRE>
130     * &lt;poolname&gt;.url         The JDBC URL for the database
131     * &lt;poolname&gt;.user        A database user (optional)
132     * &lt;poolname&gt;.password    A database user password (if user specified)
133     * &lt;poolname&gt;.maxconn     The maximal number of connections (optional)
134     * </PRE>
135     *
136     * @param props The connection pool properties
137     */

138    private void createPools(Properties props) {
139        Enumeration propNames = props.propertyNames();
140        while (propNames.hasMoreElements()) {
141            String name = (String) propNames.nextElement();
142            if (name.endsWith(".url")) {
143                String poolName = name.substring(0, name.lastIndexOf("."));
144                String url = props.getProperty(poolName + ".url");
145                if (url == null{
146                    log("No URL specified for " + poolName);
147                    continue;
148                }

149                String user = props.getProperty(poolName + ".user");
150                String password = props.getProperty(poolName + ".password");
151                String maxconn = props.getProperty(poolName + ".maxconn""0");
152                int max;
153                try {
154                    max = Integer.valueOf(maxconn).intValue();
155                }

156                catch (NumberFormatException e) {
157                    log("Invalid maxconn value " + maxconn + " for " + poolName);
158                    max = 0;
159                }

160                DBConnectionPool pool = 
161                    new DBConnectionPool(poolName, url, user, password, max);
162                pools.put(poolName, pool);
163                log("Initialized pool " + poolName);
164            }

165        }

166    }

167    
168    /**
169     * Loads properties and initializes the instance with its values.
170     */

171    private void init() {
172        InputStream is = getClass().getResourceAsStream("/db.properties");
173        Properties dbProps = new Properties();
174        try {
175            dbProps.load(is);
176        }

177        catch (Exception e) {
178            System.err.println("Can't read the properties file. " +
179                "Make sure db.properties is in the CLASSPATH");
180            return;
181        }

182        String logFile = dbProps.getProperty("logfile""DBConnectionManager.log");
183        try {
184            log = new PrintWriter(new FileWriter(logFile, true), true);
185        }

186        catch (IOException e) {
187            System.err.println("Can't open the log file: " + logFile);
188            log = new PrintWriter(System.err);
189        }

190        loadDrivers(dbProps);
191        createPools(dbProps);
192    }

193    
194    /**
195     * Loads and registers all JDBC drivers. This is done by the
196     * DBConnectionManager, as opposed to the DBConnectionPool,
197     * since many pools may share the same driver.
198     *
199     * @param props The connection pool properties
200     */

201    private void loadDrivers(Properties props) {
202        String driverClasses = props.getProperty("drivers");
203        StringTokenizer st = new StringTokenizer(driverClasses);
204        while (st.hasMoreElements()) {
205            String driverClassName = st.nextToken().trim();
206            try {
207                Driver driver = (Driver) 
208                    Class.forName(driverClassName).newInstance();
209                DriverManager.registerDriver(driver);
210                drivers.addElement(driver);
211                log("Registered JDBC driver " + driverClassName);
212            }

213            catch (Exception e) {
214                log("Can't register JDBC driver: " +
215                    driverClassName + ", Exception: " + e);
216            }

217        }

218    }

219    
220    /**
221     * Writes a message to the log file.
222     */

223    private void log(String msg) {
224        log.println(new Date() + "" + msg);
225    }

226    
227    /**
228     * Writes a message with an Exception to the log file.
229     */

230    private void log(Throwable e, String msg) {
231        log.println(new Date() + "" + msg);
232        e.printStackTrace(log);
233    }

234    
235    /**
236     * This inner class represents a connection pool. It creates new
237     * connections on demand, up to a max number if specified.
238     * It also makes sure a connection is still open before it is
239     * returned to a client.
240     */

241    class DBConnectionPool {
242        private int checkedOut;
243        private Vector freeConnections = new Vector();
244        private int maxConn;
245        private String name;
246        private String password;
247        private String URL;
248        private String user;
249        
250        /**
251         * Creates new connection pool.
252         *
253         * @param name The pool name
254         * @param URL The JDBC URL for the database
255         * @param user The database user, or null
256         * @param password The database user password, or null
257         * @param maxConn The maximal number of connections, or 0
258         *   for no limit
259         */

260        public DBConnectionPool(String name, String URL, String user, String password, 
261                int maxConn) {
262            this.name = name;
263            this.URL = URL;
264            this.user = user;
265            this.password = password;
266            this.maxConn = maxConn;
267        }

268        
269        /**
270         * Checks in a connection to the pool. Notify other Threads that
271         * may be waiting for a connection.
272         *
273         * @param con The connection to check in
274         */

275        public synchronized void freeConnection(Connection con) {
276            // Put the connection at the end of the Vector
277            freeConnections.addElement(con);
278            checkedOut--;
279            notifyAll();
280        }

281        
282        /**
283         * Checks out a connection from the pool. If no free connection
284         * is available, a new connection is created unless the max
285         * number of connections has been reached. If a free connection
286         * has been closed by the database, it's removed from the pool
287         * and this method is called again recursively.
288         */

289        public synchronized Connection getConnection() {
290            Connection con = null;
291            if (freeConnections.size() > 0{
292                // Pick the first Connection in the Vector
293                // to get round-robin usage
294                con = (Connection) freeConnections.firstElement();
295                freeConnections.removeElementAt(0);
296                try {
297                    if (con.isClosed()) {
298                        log("Removed bad connection from " + name);
299                        // Try again recursively
300                        con = getConnection();
301                    }

302                }

303                catch (SQLException e) {
304                    log("Removed bad connection from " + name);
305                    // Try again recursively
306                    con = getConnection();
307                }

308            }

309            else if (maxConn == 0 || checkedOut < maxConn) {
310                con = newConnection();
311            }

312            if (con != null{
313                checkedOut++;
314            }

315            return con;
316        }

317        
318        /**
319         * Checks out a connection from the pool. If no free connection
320         * is available, a new connection is created unless the max
321         * number of connections has been reached. If a free connection
322         * has been closed by the database, it's removed from the pool
323         * and this method is called again recursively.
324         * <P>
325         * If no connection is available and the max number has been 
326         * reached, this method waits the specified time for one to be
327         * checked in.
328         *
329         * @param timeout The timeout value in milliseconds
330         */

331        public synchronized Connection getConnection(long timeout) {
332            long startTime = new Date().getTime();
333            Connection con;
334            while ((con = getConnection()) == null{
335                try {
336                    wait(timeout);
337                }

338                catch (InterruptedException e) {}
339                if ((new Date().getTime() - startTime) >= timeout) {
340                    // Timeout has expired
341                    return null;
342                }

343            }

344            return con;
345        }

346        
347        /**
348         * Closes all available connections.
349         */

350        public synchronized void release() {
351            Enumeration allConnections = freeConnections.elements();
352            while (allConnections.hasMoreElements()) {
353                Connection con = (Connection) allConnections.nextElement();
354                try {
355                    con.close();
356                    log("Closed connection for pool " + name);
357                }

358                catch (SQLException e) {
359                    log(e, "Can't close connection for pool " + name);
360                }

361            }

362            freeConnections.removeAllElements();
363        }

364        
365        /**
366         * Creates a new connection, using a userid and password
367         * if specified.
368         */

369        private Connection newConnection() {
370            Connection con = null;
371            try {
372                if (user == null{
373                    con = DriverManager.getConnection(URL);
374                }

375                else {
376                    con = DriverManager.getConnection(URL, user, password);
377                }

378                log("Created a new connection in pool " + name);
379            }

380            catch (SQLException e) {
381                log(e, "Can't create a new connection for " + URL);
382                return null;
383            }

384            return con;
385        }

386    }

387}
2007-05-16 18:20 | klvt

# re: 一个简化的java线程池示例  回复  更多评论   

扁担长板凳宽扁担想绑在板凳板凳不让扁担绑在板凳上扁担偏要绑在板凳板凳偏偏不让扁担绑在那板凳

2007-05-18 16:39 | klvt

# re: 一个简化的java线程池示例  回复  更多评论   

JDK1.5中已经提供线程池的支持了 java.util.concurrent 包
2007-06-15 15:41 | jasson

只有注册用户登录后才能发表评论。


网站导航: