关于并发的零碎知识

来源:互联网 发布:mac如何修改ppt格式 编辑:程序博客网 时间:2024/05/01 10:58

一、线程本地存储(ThreadLocal

防止任务在共享资源上产生冲突的方式就是避免使用同步。即根除对变量的共享。线程本地存储是一种自动化机制,可以为使用相同变量的每个不同的线程都创建不同的存储。因此,如果你有5个线程都要使用变量x所表示的对象,那线程本地存储就会生成5个用于x的不同存储块。主要是,它们使得你可以将状态与线程关联起来。

创建和管理线程本地存储可以用 java.lang.ThreadLocal类来实现。

ThreadLocal对象通常当做静态域存储。在创建ThreadLocal时,你只能通过get()set()方法来访问对象的内容,其中,get()方法将返回与其线程相关联的对象的副本,而set()方法会将参数插入带为其线程存储的对象中,并返回存储中原有的对象。Get()方法不是synchronized的,因为ThreadLocal保证不会出现竞争条件。

二、Executor

在Java中有两种通过线程来执行任务的策略:一是把所有任务放在单个线程中串行执行,二是将每个任务放在各自的线程中执行 。缺点是:串行执行的问题在于其糟糕的响应性和吞吐量,而第二种的为题在于资源管理的复杂性。

在Java类库中,任务执行的主要抽象不是Thread,而是Executor.虽然Executor是个简单的接口,但它却为灵活且强大的一部任务执行框架提供了基础,该框架能直吹多种不同类型的任务执行策略。它提供了一种标准的方法将任务的提交过程与执行过程解耦开来,并用Runnable来表示任务。Executor的实现还提供了对生命周期的支持。

通过使用Executor,将请求处理任务的提交与任务的实际执行解耦开来,并且只需采用另一种不同的Executor实现就可以改变服务器的行为。改变Executor实现或配置所带来的影响要远远小于改变任务提交方式带来的影响。

如果你希望获得一种更灵活的执行策略,考虑使用Executor代替Thread。

线程池

从字面含义来看,是指管理一组同构工作线程的资源池。线程池工作时会有一个工作队列与他相关,工作队列中保存可所有等待执行的任务,工作者线程从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。优势在于:通过重用现有的线程而不是创建新线程。不会等待线程的创建而延迟任务的执行,从而提高了响应性。通过适当调整线程池的大小,可以创建足够多的线程以便使处理器保持忙碌状态,同时还可以防止过多线程相互竞争资源而使应用程序耗尽内存或失败。

可以通过调用Executor中的静态工厂方法之一来创建线程池:newFixedThreadPool、newCachedThreadPool、newSingleThreadPool、newScheduleThreadPool

Executor生命周期

为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了一些用于生命周期管理的方法。ExecutorService的生命周期有三种状态:运行、关闭和已终止。

ExecutorService提供了两种关闭方法:shutdown正常关闭,shutdownNow强行关闭。在进行强行关闭时,shutdownNow首先关闭当前正在执行的任务,然后返回所有尚未启动的任务清单。差别在于:强行关闭的速度更快,但风险也更大,因为任务很可能在执行到一半时被结束:而正常关闭虽然速度慢,但却更安全,因为ExecutorService会一直等到队列中所有任务都执行完成后才关闭。

Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。ExecutorService中的所有submit方法都将返回一个Future,从而将一个Runnable或Callable提交给Executor,并得到一个Future用来获得任务的执行结果或取消任务。还可以显示的为某个指定的Runnable或Callable实例化一个FutureTask,由于FutureTask实现了Runnable,因此可以将它提交给Executor来执行,或者直接调用它的run方法。


——摘自《Java并发编程实战》

0 0
原创粉丝点击