`
snake1987
  • 浏览: 72747 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java并发学习之二:线程池

    博客分类:
  • java
阅读更多
第二步,是实现一个线程池

因为之前看书的时候留了个心眼,看线程池相关的内容的时候特意没去研究JDK的实现
因为学跟做不是一码事,写一个线程池,算是给自己看完并发实践这书的一个练习吧

废话不多说,练习开始

首先,整理一下要实现的功能,或者说要注意的元素
1.实现Executor接口
2.实现一个等待队列(可否配置,优先级等)
3.是否需要预启动线程(可否配置)
4.执行开始前,结束后,需要留接口
5.Runable在任务中的存放形式
6.线程的启动,唤醒
7.线程池的关闭(优雅地结束),需要线程提供中断,线程池提供给使用者的提示,线程池返回取消线程等
8.线程队列(空闲队列?)
9.取空闲线程算法(任务入队时?线程执行一个任务结束时?)
10.将所有需要同步的地方尽量使用非阻塞算法(通过侦察,更新一个原子变量实现)
11.减少线程切换开销(轮询是否有任务,n微秒后再进入等待)

暂时就考虑到这些,剩下的以后再补

总的来说,计划写n个版本(毕竟是第二次动手,写一个庞大的需要细致考虑的东西功力还差远呢,只能从最简单的,最方便的实现开始,然后慢慢加强)

测试先行:
	public static void main(String[] args) throws InterruptedException
	{
		testEasyRunnableThreadPool(new ThreadPoolTest1(10), 10000, 10);
		testEasyRunnableThreadPool(Executors.newFixedThreadPool(10), 10000, 10);
	}

	/**
	 * 一个产生随机数的方法,防止jvm优化
	 * @param seed
	 * @return
	 */
	static int getRandomNum(int seed)
	{
		seed ^= (seed << 6);
		seed ^= (seed >>> 21);
		seed ^= (seed << 7);
		return seed;
	}
	
	/**
	 * 执行一个简单的计算,只占用cpu,没有io和其他阻塞的方法
	 * @param pool
	 * @param tryTime
	 * @param threadNum
	 * @throws InterruptedException
	 */
	static void testEasyRunnableThreadPool(Executor pool,int tryTime,int threadNum) throws InterruptedException
	{
		//construct runnable
		Runnable command = new Runnable() {			
			public void run() {
				final int addTime = 1000000;
				long sum = 0;
				int temp = this.hashCode() ^ (int)System.currentTimeMillis();
				for(int i = 0;i<addTime;i++)
				{
					sum += (temp = getRandomNum(temp));
				}				
			}
		};		
		testThreadPool(tryTime, pool, command);
	}
	
	/**
	 * 
	 * @param tryNum 
	 * @param pool
	 * @param commandList
	 * @throws InterruptedException
	 */
	static void testThreadPool(int tryNum,Executor pool,final Runnable command) throws InterruptedException
	{
		final CountDownLatch latch = new CountDownLatch(tryNum);
		Runnable wrapper = new Runnable() {			
			public void run() {
				command.run();
				//想测试并发,在并发中加入适当的同步操作是无法避免的,只能减少
				//,在这,只是做了一个简单的countdown,影响不大
				latch.countDown();
			}
		};
		long startTime = System.nanoTime();
		for(int i = 0;i<tryNum;i++)
		{
			pool.execute(wrapper);
		}		
		latch.await();
		long endTime = System.nanoTime();
		System.out.println(endTime-startTime);
	}




线程池代码:
第一版本的目标很简单,只要能跑,没死锁,就是完胜
可惜结果很让人绝望~
写完了,调了近3个小时,仍然没发现问题,最后加了一堆输出,又加了多个锁,终于勉勉强强跑起来了……
并发的调试真难,debug完全没用,看输出又看不出什么来,只能是一遍一遍地检查代码,写下一个版本前先找点资料,研究下调试方法吧
后来发现错误是一个简单的i++……
public class ThreadPoolTest1 implements Executor {
	//等待队列
	Queue<Runnable> waitingQueue = null;
	
	ConcurrentLinkedQueue<ThreadNode> freeThread;
	//相当于一个freeThread的状态,根据状态决定行为,原则上将freeThread.size()+busyThreadsNum=MAXTHREADNUM
	private AtomicInteger busyThreadsNum = new AtomicInteger(0);
	//最大线程数
	final int MAXTHREADNUM;
	
	public ThreadPoolTest1 (int threadNum)
	{
		this.MAXTHREADNUM = threadNum;
		init(MAXTHREADNUM,new ConcurrentLinkedQueue<Runnable>());
	}	

	private void init(int threadNum,ConcurrentLinkedQueue<Runnable> queue)
	{
		freeThread = new ConcurrentLinkedQueue<ThreadNode>();
		waitingQueue = queue;
		//初始化空线程,一开始不是这样实现的,后来发现一堆问题,暂时只能先加锁,无论怎么样,跑起来再说把
		synchronized(this)
		{
			for(int i = 0;i<threadNum;i++)
			{
				ThreadNode node = new ThreadNode();
				busyThreadsNum.incrementAndGet();				
				node.start();
			}
		}
	}
	
	private synchronized void threadExecute(Runnable command)
	{
		//用了个挺弱智的非阻塞算法
		for(;;)
		{
			//得到开始的值
			int expect = busyThreadsNum.get();
			if(expect == MAXTHREADNUM)
			{
				waitingQueue.add(command);
				return;
			}
			else
			{
				//比较并设置,如果失败,重来
				if(busyThreadsNum.compareAndSet(expect, ++expect))//之前写的是expect++,检查了n久,硬是看不出啥问题,只能怪自己天资愚鲁吧
				{
					ThreadNode t = freeThread.remove();
					t.setCommand(command);
					synchronized(t)
					{t.notify();}
					return;
				}
				else
					continue;
			}
		}

	}
	
	private class ThreadNode extends Thread
	{
		Runnable command = null;
		Exception e = null;
		
		Exception getException()
		{
			return e;
		}
		
		void setCommand(Runnable c)
		{
			command = c;
		}
		
		
		@Override
		public void run() {
			try {
				for(;;)
				{
					if(command == null)
					{					
						ThreadPoolTest1.this.waitThread(this);					
					}
					command.run();				
					command = ThreadPoolTest1.this.getCommand();			
				}
			}catch (InterruptedException e) {
			}
		}
	}
	
	Runnable getCommand() throws InterruptedException
	{
		return waitingQueue.poll();
	}
	
	void waitThread(Thread t) throws InterruptedException
	{
		synchronized(this)
		{		
			freeThread.add((ThreadNode) t);
			busyThreadsNum.decrementAndGet();
		}
		synchronized(t)
		{
			t.wait();					
		}

	}
	
	protected void beforeExecute()
	{
		
	}

	public void execute(Runnable command) {
		beforeExecute();		
		threadExecute(command);
		afterExecute();

	}
	
	protected void afterExecute()
	{
		
	}
}


第一版本就写成这样了,之后再慢慢加强了,毕竟学java第一个玩意儿也是helloworld,原谅自己了
分享到:
评论

相关推荐

    Java并发编程:线程池的使用 - 平凡希 - 博客园1

    Java并发编程中的线程池是提高系统效率的关键工具,它解决了频繁创建和销毁线程的问题。线程池通过复用已存在的线程来处理任务,从而避免了每次任务执行完毕后销毁线程的开销。在Java中,线程池的核心实现是`java....

    java并发编程:juc线程池

    Java并发编程中的JUC线程池是Java程序员必须掌握的关键技术之一,它允许开发者高效地管理并发执行的任务,充分利用多核处理器的性能。线程池的出现解决了在并发环境中线程创建、销毁带来的开销,提高了系统资源的...

    线程池详解:线程池七大核心参数、线程池工作原理、线程池的创建方式、线程池的拒绝策略、如何合理分配线程池大小

    线程池是Java多线程编程中的重要概念,它是一种管理线程的机制,通过池化技术有效地管理和控制线程的生命周期,以提高系统资源的...通过持续学习和实践,我们可以更好地驾驭线程池,提升系统的并发处理能力和响应速度。

    Java8并行流中自定义线程池操作示例

    Java8并行流中自定义线程池操作示例 Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了...

    JAVA并发编程实践-线程池-学习笔记

    Java并发编程实践中的线程池是一个关键的概念,它在多线程编程中扮演着至关重要的角色,有效地管理和调度线程资源,以提高系统的性能和效率。线程池通过复用已存在的线程来减少线程的创建和销毁开销,避免了频繁的上...

    Java分布式应用学习笔记07线程池应用

    线程池是Java并发编程的核心技术之一,它通过复用一组预创建的线程来执行任务,从而减少了创建和销毁线程的开销,提高了系统的响应速度和处理能力。 #### 线程池的作用 线程池可以显著提高多线程应用的性能和效率...

    聊聊并发(3)Java线程池的分析和使用Java开发Jav

    在Java编程中,线程池是一种管理线程资源的有效方式,它可以提高...在阅读《聊聊并发(3)Java线程池的分析和使用》这份文档时,你可以学习到更多关于线程池的实践技巧和案例分析,这对于提升Java开发能力大有裨益。

    Java并发编程:设计原则与模式(第二版)-3

    《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java多线程编程技术的权威著作。这本书详细阐述了在Java平台中进行高效并发处理的关键概念、设计原则和实用模式。以下是对该书内容的一些核心知识点的概述...

    Java 并发学习笔记:进程和线程,并发理论,并发关键字,Lock 体系,原子操作类,发容器 &amp; 并发工具,线程池,并发实践

    Java 并发学习笔记: 进程和线程, 并发理论, 并发关键字, Lock 体系, 原子操作类, 发容器 & 并发工具, 线程池, 并发实践 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的...

    java并发笔记,包含线程池

    Java并发编程是Java开发中的重要领域,特别是在大型系统和服务器端应用中,高效地利用多核处理器资源,实现高并发性能至关重要。...通过深入学习和实践,开发者可以更好地驾驭Java并发,提升程序的性能和稳定性。

    java线程池实例详细讲解

    Java线程池是一种高效管理线程资源的工具,它能够帮助开发者有效地控制并调度线程,从而提升系统性能,减少系统资源的浪费。...通过深入学习和实践,我们可以更好地利用线程池来优化我们的Java应用程序。

    MultiThread_并发_java_线程池_

    Java并发编程是提升系统性能的关键,理解并熟练运用线程池可以有效地管理线程资源,提高系统的响应速度和并发能力。在实际项目中,合理设计和配置线程池,结合具体业务需求,能够使程序运行更加稳定、高效。通过阅读...

    java 并发编程的艺术pdf清晰完整版 源码

    《Java并发编程的艺术》这本书是Java开发者深入理解并发编程的重要参考书籍。这本书全面地介绍了Java平台上的并发和多线程编程技术,旨在帮助开发者解决在实际工作中遇到的并发问题,提高程序的性能和可伸缩性。 ...

    Java 线程池的原理与实现

    Java线程池是一种高级的多线程处理框架,它是Java并发编程中非常重要的一个组件。线程池的原理和实现涉及到操作系统调度、内存管理和并发控制等多个方面。理解线程池的工作原理有助于优化程序性能,避免过度创建和...

    Java并发编程:设计原则与模式(第二版).rar

    通过学习《Java并发编程:设计原则与模式(第二版)》,开发者可以掌握Java并发编程的核心技术和最佳实践,提升在多线程环境下的编程能力。书中的实例和实战经验将帮助读者在实际开发中避免常见的并发陷阱,编写出...

    java并发编程实战源码,java并发编程实战pdf,Java

    通过学习《Java并发编程实战》的源码,你可以更直观地了解这些概念如何在实际代码中实现,从而提升你的并发编程能力。在IDE中运行这些示例,可以加深对并发原理的理解,同时也能锻炼解决问题的能力。记住,实践是...

    java并发编程与实践

    通过深入学习"Java并发编程与实践"文档,开发者能够提升自己在高并发环境下的编程能力,设计出更加健壮和高效的Java应用程序。这份资料对于理解Java并发原理、优化并发代码和解决并发问题具有极大的价值。

    Java中多线程的使用线程池.docx

    Java中的线程池是多线程编程中一种高效、可管理的执行机制。它通过预先创建并维护一组线程,避免了频繁地创建和销毁线程带来的开销,从而提高了程序的性能和响应速度。线程池的核心概念包括以下几个方面: 1. **...

    JAVA线程池原理以及几种线程池类型介绍

    ### JAVA线程池原理及几种...综上所述,线程池是Java并发编程中的一个重要概念,它可以帮助开发者更高效地管理线程资源,提高应用程序的性能。理解线程池的工作原理及其配置细节,对于构建高性能的并发应用至关重要。

    java线程池封装j

    Java线程池封装是Java并发编程中重要的一环,合理的线程池配置和封装能显著提升程序的性能和稳定性。理解线程池的工作原理,根据业务需求选择合适的参数,以及正确处理拒绝策略,都是实现高效并发处理的关键。在实际...

Global site tag (gtag.js) - Google Analytics