java 保持固定接数_Java线程详解(四)

【Java线程:线程池】

线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。

在Java5之前,要实现一个线程池是相当有难度的,现在我们只需要按照提供的API来使用,即可享受线程池带来的极大便利。

在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建连接池的静态方法,是必须掌握的。

一、固定大小的线程池f7cf4db898e6a455837f75eb77fdf7ad.png

运行结果:dad364657225df615df00d38258a2cc9.png

二、单任务线程池

在上例的基础上改一行创建pool对象的代码为:1f0236395d75ccaba248e9e54ea72806.png

运行结果:1585246d3b4e2c407ccfe2fccfbefd6a.png

对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。

一旦池中有线程完毕,则排队等待的某个线程会入池执行。

三、可变尺寸的线程池

与上面的类似,只是改动下pool的创建方式:b0f605ef968711877ff98a5015ceea92.png

运行结果:ea9978906f0b1504c8ad3ac7b32d506b.png

四、延迟连接池6e9db5a8d401a3abfda12ebe04d40908.png

运行结果:76f26bcbc19cff84f041a54ba29d63b2.png

五、单任务延迟连接池

在上面代码基础上,做改动98c78e27de75a11fdeb6504655a6abc1.png

运行结果:1585246d3b4e2c407ccfe2fccfbefd6a.png

六、自定义线程池3ae645234ea13701b8b43f9f403d8c35.png

运行结果:0c35ee82f81d18b164d3db0cbaab6d62.png

创建自定义线程池的构造方法很多,本例中参数的含义如下:

ThreadPoolExecutor90aed6b226a604715665dba0a03b47b9.png

参数:

corePoolSize -池中所保存的线程数,包括空闲线程。

maximumPoolSize -池中允许的最大线程数。

keepAliveTime -当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

unit - keepAliveTime参数的时间单位。

workQueue -执行前用于保持任务的队列。此队列仅保持由execute方法提交的Runnable任务。

抛出:

IllegalArgumentException-如果 corePoolSize或 keepAliveTime小于零,或者 maximumPoolSize小于或等于零,或者 corePoolSize大于 maximumPoolSize。

NullPointerException -如果workQueue为 null

自定义连接池稍微麻烦些,不过通过创建的ThreadPoolExecutor线程池对象,可以获取到当前线程池的尺寸、正在执行任务的线程数、工作队列等等。

【Java线程:有返回值的线程】

在Java5之前,线程是没有返回值的,常常为了“有”返回值,破费周折,而且代码很不好写。或者干脆绕过这道坎,走别的路了。

现在Java终于有可返回值的任务(也可以叫做线程)了。

可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。

下面是个很简单的例子:dbf02a4e78ea9d13dfc599ce07eb69d4.png

运行结果:41fdebb042741aa1e46447a6f1007b50.png

【Java线程:锁(上)】

利用锁可以方便的实现资源的封锁,用来控制对竞争资源并发访问的控制,这些内容主要集中在java.util.concurrent.locks包下面,里面有三个重要的接口Condition、Lock、ReadWriteLock。5243a21f92d6e06dfafb413d798b718c.png

看个例子:a047d19ab81e89085d641d768682c093.png

运行结果:60d2f36fda21eab518238631de8d6c79.png

从上面的输出可以看到,利用锁对象太方便了,比直接在某个不知情的对象上用锁清晰多了。

但一定要注意的是,在获取了锁对象后,用完后应该尽快释放锁,以便别的等待该锁的线程有机会去执行。

【Java线程:锁(下)】

在上文中提到了Lock接口以及对象,使用它,很优雅的控制了竞争资源的安全访问,但是这种锁不区分读写,称这种锁为普通锁。为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。

Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock,也有具体的实现ReentrantReadWriteLock,详细的API可以查看JavaAPI文档。

下面这个例子是在上文例子的基础上,将普通锁改为读写锁,并添加账户余额查询的功能,代码如下:2bb93bfe23e9fda65faedd3f22dc56ed.png

运行结果:c352260ff21bbfaf1b63287a5564bea4.png

在实际开发中,最好在能用读写锁的情况下使用读写锁,而不要用普通锁,以求更好的性能。

阅读更多:7a51e053b34a7b31dcaec6526f4d34dc.png

4d1a357239336b73947af54110761444.png

01c7ea076e4c45e6d85ff93d7286956c.png

5a6248719eab539b6cda4d7ca48f5a7b.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值