并发编程(七):线程应用实例

目录


学习资料

《Java并发编程的艺术》第4章 4.4


1.等待超时模式

等待超时伪代码如下:

// 对当前对象加锁 
public synchronized Object get(long mills) throws InterruptedException { 
	long future = System.currentTimeMillis() + mills; 
	long remaining = mills; 
	// 当超时大于0并且result返回值不满足要求 
	while ((result == null) && remaining > 0) { 
		wait(remaining);
         remaining = future - System.currentTimeMillis(); 
	} 
	return result; 
}

针对昂贵资源的获取都应该加以超时限制,如数据库连接


2.简单数据库连接池

核心代码:获取数据库连接(设置超时时间)

public class ConnectionPool { 
	private LinkedList<Connection> pool = new LinkedList<Connection>(); 
	//构造连接
	public ConnectionPool(int initialSize) { 
		if (initialSize > 0) { 
			for (int i = 0; i < initialSize; i++) { 
				pool.addLast(ConnectionDriver.createConnection()); 
			} 
		} 	
	}
	//释放连接
	public void releaseConnection(Connection connection) { 
		if (connection != null) { 
			synchronized (pool) { 
				// 连接释放后需要进行通知,这样其他消费者能够感知到连接池中已经归还了一个连接 
				pool.addLast(connection); 
				pool.notifyAll(); 
			} 
		} 
	}

	// 在mills内无法获取到连接,将会返回null 
	public Connection fetchConnection(long mills) throws InterruptedException { 
		synchronized (pool) { 
				// 完全超时 
			if (mills <= 0) { 
				while (pool.isEmpty()) { 
					pool.wait(); 
				}
				return pool.removeFirst(); 
			} else {
				long future = System.currentTimeMillis() + mills; 
				long remaining = mills; 
				while (pool.isEmpty() && remaining > 0) { //没有可用连接且等待时间未结束
					pool.wait(remaining); 
					remaining = future - System.currentTimeMillis(); 
				}
				Connection result = null; 
				if (!pool.isEmpty()) { 
					result = pool.removeFirst(); 
				}
				return result; 
			} 
		} 
	}
}

3.线程池简介

线程的创建/销毁需要耗费系统资源,过多的线程会增加系统负载

线程池好处:

  • 消除了频繁创建和销毁线程的系统资源开销
  • 面对过量任务的提交能够平缓的劣化

简单的线程池接口定义:

public interface ThreadPool<Job extends Runnable> { 
	// 执行一个Job,这个Job需要实现Runnable 
	void execute(Job job); 
	// 关闭线程池 
	void shutdown(); 
	// 增加工作者线程 
	void addWorkers(int num); 
	// 减少工作者线程 
	void removeWorker(int num); 
	// 得到正在等待执行的任务数量 
	int getJobSize(); 
}

线程池本质就是使用了一个线程安全的工作队列连接工作者线程和客户端线程,客户端线程将任务放入工作队列后便返回,工作者线程不断从工作队列上取出工作并执行;工作队列为空,工作者线程等待;大量任务提交,会有更多工作者线程被创建(一般模式)

简单的ThreadPool实现应包含的方法及元素:(不包含实现代码)

public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> { 
    // 线程池最大限制数 
    private static final int MAX_WORKER_NUMBERS = 10; 
    // 线程池默认的数量 
    private static final int DEFAULT_WORKER_NUMBERS = 5; 
    // 线程池最小的数量 
    private static final int MIN_WORKER_NUMBERS = 1; 
    // 这是一个工作列表,将会向里面插入工作 
    private final LinkedList<Job> jobs = new LinkedList<Job>(); 
    // 工作者列表 
    private final List<Worker> workers = Collections.synchronizedList(new 
    ArrayList<Worker>()); 
    // 工作者线程的数量 
    private int workerNum = DEFAULT_WORKER_NUMBERS; 
    // 线程编号生成 
    private AtomicLong threadNum = new AtomicLong(); 
    
    //无参构造器
    public DefaultThreadPool() { 
        //创建默认大小的线程池,调用initializeWokers
    }
    //初始化num个worker线程
    public DefaultThreadPool(int num) { 
  		//这里要对num的有效性验证,转换
        //创建Worker线程并加入队列,调用initializeWokers
    }
    //执行方法
    public void execute(Job job) {
        //执行,需要进行同步,通知
    }
    //关闭线程池
    public void shutdown() {
        //关闭线程池,遍历线程执行每一个的shutdown方法
    }
    //添加num个Worker线程
    public void addWorkers(int num) {
        //创建线程并加入Worker线程队列,调用initializeWokers
    }
    //停止num个Worker线程
    public void removeWorker(int num) {
        //对num个线程执行shutdown
    }
    //获取工作队列长度
    public int getJobSize() {
        return jobs.size();
    }
    // 初始化线程工作者
    private void initializeWokers(int num) {
        //创建num个线程并加入worker队列
    }
    
    // 工作者,负责消费任务 
    class Worker implements Runnable { 
        // 是否工作 
        private volatile boolean running = true; 
        public void run() { 
            while (running) { 
                //消费者消费工作队列的任务,需要进行同步
            } 
        }
        //关闭工作者
        public void shutdown() { 
            running = false; 
        } 
    } 
}      

4.基于线程池的Web服务器

简单的Http服务器实现应包含的方法及元素:(不包含实现代码)

public class SimpleHttpServer {
    // 处理HttpRequest的线程池 
    static ThreadPool<HttpRequestHandler> threadPool = new DefaultThreadPool 
    <HttpRequestHandler>(1); 
    // SimpleHttpServer的根路径 
    static String basePath; 
    static ServerSocket serverSocket; 
    // 服务监听端口 	
    static int port = 8080; 
    //设置服务监听端口
    public static void setPort(int port) {...}
    //设置根路径
    public static void setBasePath(String basePath) {...}
    
    // 启动SimpleHttpServer 
    public static void start() throws Exception { 
        serverSocket = new ServerSocket(port);Socket socket = null; 
        while ((socket = serverSocket.accept()) != null) { 
            // 接收一个客户端Socket,生成一个HttpRequestHandler,放入线程池执行 
            threadPool.execute(new HttpRequestHandler(socket)); 
        }
        serverSocket.close(); 
    }
    
    //静态内部类HttpRequestHandler,处理HttpRequest
    static class HttpRequestHandler implements Runnable { 
        //socket套接字
        private Socket socket;
        //设置套接字
        public HttpRequestHandler(Socket socket) {
            this.socket = socket; 
        }
        @Override 
        public void run() {
            //处理请求的线程代码
        }
    }
    // 关闭流或者Socket 
    private static void close(Closeable... closeables) { 
        //调用对象的close方法
    }
}

时序图:


posted @ 2021-03-11 20:54  菜鸟kenshine  阅读(108)  评论(0编辑  收藏  举报