七.Callable和Future接口
C#可以把任意方法包装成线程执行体,包括那些有返回值的方法。Java也从jdk1.5开始,加入了Callable接口用来扩展Runnable接口的功能,Callable接口提供一个call()来增强Runnable的run()。因为call()可以有返回值,可以声明抛出异常。
但是Callable是新增的接口并没有继承Runnable接口,那么肯定不能作为Runnabletarget来直接作为Thread构造方法的参数。必须由一个中间的类来包装Callable对象。这个类就是实现了Future接口(继承至Runnable接口)的FutureTask类。
CODE:
八.线程池
Jdk1.5后java也内置支持线程池,为了提高性能。(当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池)
Jdk1.5提供一个Executors工厂类来产生线程池。工厂类中包含5个静态工厂方法来创建线程池:
一.返回类型是ExecutorService的共3个:
1.newFixedThreadPool(intnThreads)
创建一个可重用的,具有固定线程数的线程池
CODE:
2.ExecutorServicenewCachedThreadPool()
创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中。
CODE:
3.newSingleThreadExecutor()
创建一个只有单线程的线程池,等于newFixedThreadPool(1)。
CODE:
二.返回类型是ScheduledExecutorService(是ExecutorService的子类)的共2个:
1.newSingleThreadScheduledExecutor()
创建只有一条线程的线程池,它可以在指定延迟后执行线程任务
CODE:
2.newScheduledThreadPool(intcorePoolSize)
创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务。其中参数指池中所保存的线程数,即使线程时空闲的也被保存在线程池内。
CODE:
ExecutorService代表尽快执行线程的线程池(只要线程池中有空闲线程立即执行线程任务),程序只需要传入Runnable或Callable对象即可。
ExecutorService提供三个方法来执行线程:
1.Future<?>submit(Runnabletarget):Runnable中run是没有返回值的所以执行完成后返回null,可以调用Future的isDone(),isCanclled()来判断当前target的执行状态。
2.<T>Future<T>submit(Runnabletarget,Tresult):因为Runnable中run是没有返回值,这里显示指定该Runnable对象线程执行完成返回一个值,这个值就是result。
3.<T>Future<T>submit(Callable<T>target):Callable中的call是有返回值的
ScheduledExecutorService提供以下四个方法:
1.ScheduledFuture<V>schedule(Callable(V)c,longdelay,TimeUnitunit):指定c任务将在delay延迟后执行。
2.ScheduledFuture<?>shedule(Runnabler,longdelay,TimeUnitunit):指定r任务将在delay延迟后执行。
3.ScheduledFuture<?>scheduleAtFixedRate(Runnabler,longinitialDelay,longperiod,TimeUnitunit):指定r任务将在delay延迟后执行,而且以设定的频率重复执行(在initialDelay后开始执行,然后开始依次在initialDelay+period,initialDelay+period*2...处重复执行)。
4.ScheduledFuture<?>scheduledWithFixedDelay(Runnabler,longnitialDelay,longdelay,TimeUnitunit):创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行中止和下一次执行开始之间都存在给定的延迟。如果任务的任意依次执行时异常,就会取消后序执行。否则,只能通过程序来显示取消或中止该任务。
当用完一个线程池后,应该调用该线程池的shutdown()方法,启用了shutdown()方法后线程池不再接受新任务,但会将以前所有已提交的任务执行完成,然后启动线程池的关闭序列。
当线程池所有任务都执行完成后,池中所有线程都会死亡,另外也可以调用线程池的shutdownNow()方法来关闭线程池,该方法试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
例子:
九.附录:线程相关的类
1.ThreadLocal(线程局部变量)
为了避免并发线程的安全问题,可以添加支持泛型的ThreadLocal类(ThreadLocal<T>)。通过使用ThreadLocal可以简化多线程编程时的并发访问,使用这个工具类可以很简洁的写出有没的多线程程序(例如Hibernate的官方提供HibernateUtil类里设置当前线程的局部变量是当前线程副本中session的值):
Hibernate代码:
根据上面代码来看:
线程局部变量功能很简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。仿佛就好像每一个线程都可以完全拥有该变量
ThreadLocal类提供的常用方法:
1.Tget():返回此线程局部变量中当前线程副本中的值。
2.voidremove():删除此线程局部变量中当前线程的值。
3.voidset(Tvalue):设置此线程局部变量中当前线程副本中的值。
CODE:
结果:
-------初始化(为ThreadLocal在main中副本)值是:ThreadLocal本尊
0------pool-1-thread-1线程局部变量副本值:null
1------pool-1-thread-1线程局部变量副本值:null
2------pool-1-thread-1线程局部变量副本值:pool-1-thread-1
0------pool-1-thread-2线程局部变量副本值:null
1------pool-1-thread-2线程局部变量副本值:null
2------pool-1-thread-2线程局部变量副本值:pool-1-thread-2
0------pool-1-thread-3线程局部变量副本值:null
1------pool-1-thread-3线程局部变量副本值:null
2------pool-1-thread-3线程局部变量副本值:pool-1-thread-3
总结:
ThreadLocal并不能代替同步机制,两者面向的问题领域不同,同步机制是为了多个线程同步对相同资源的并发访问,是多个线程之间进行通信的有效方式。而ThreadLocal是隔离多个线程的数据共享,根本就没有在多个线程之间共享资源,也就更不用对多个线程同步了。
所以:如果进行多个线程之间共享资源,达到线程之间通信功能,就同步。
如果仅仅需要隔离多个线程之间的共享冲突,就是用ThreadLocal。
1.包装线程不安全的集合成为线程安全集合
Java集合中的ArrayList,LinkedList,HashSet,TreeSet,HashMap都是线程不安全的(线程不安全就是当多个线程想这些集合中放入一个元素时,可能会破坏这些集合数据的完整性)
如何将上面的集合类包装成线程安全的呢?
例子:使用Collections的synchronizedMap方法将一个普通HashMap包装成线程安全的类
HashMaphm=Collections.synchronizedMap(newMap());
如果需要包装某个集合成线程安全集合,则应该在创建之后立即包装如上。
3.线程安全的集合类
位于java.util.concurrent包下的ConcurrentHashMap集合和ConcurrentLinkedQueue集合都支持并发访问,分别对应支持并发访问的HashMap和Queue,它们都可以支持多线程并发写访,这些写入线程的所有操作都是线程安全的,但读取的操作不必锁定。(为什么?因为算法我也看不懂)
当多个线程共享访问一个公共集合时,使用ConcurrentLinkedQueue是一个恰当的选择,因为ConcurrentLinkedQueue不允许使用null元素。ConcurrentLinkedQueue实现了多线程的高效访问,多线程访问ConcurrentLinkedQueue集合时不需要等待。
ConcurrentHashMap支持16条多线程并发写入。
用迭代器访问这两种可支持多线程的集合而言,该迭代器可能不反应出创建迭代器之后所做的修改,但不会抛出异常,而如果Collection作为对象,迭代器创建之后修改,则会抛出ConcurrentModificationException。
分享到:
相关推荐
这篇学习笔记将深入探讨Java多线程的核心概念、实现方式以及相关工具的使用。 一、多线程基础 1. 线程与进程:在操作系统中,进程是资源分配的基本单位,而线程是程序执行的基本单位。每个进程至少有一个主线程,...
java学习笔记2(多线程)java学习笔记2(多线程)
线程同步是为了避免多线程环境下的数据竞争问题,Java提供了多种同步机制。同步方法通过`synchronized`关键字修饰,确保同一时间只有一个线程能访问该方法。同步块(Synchronized Block)更灵活,可以指定同步的代码...
多线程学习笔记 iOS开发中,多线程是一种常见的技术手段,用于优化应用程序的性能,提升用户体验。多线程的核心是让程序能够并发地执行多个任务,合理地利用设备的计算能力,尤其是在拥有多个核心的处理器上。 ...
基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码....
本笔记全面涵盖了多线程的学习,包括基础理论和实践代码,旨在帮助开发者深入理解并掌握Java多线程技术。 一、线程基础知识 线程是操作系统分配CPU时间的基本单位,一个进程中可以包含多个线程。Java通过`Thread`类...
这篇文档和对应的源代码 博文链接:https://interper56-sohu-com.iteye.com/blog/172303
java学习笔记5(java多线程)java学习笔记5(java多线程)
Java并发编程学习笔记,研究JAVA并发多线程编程的一本教程,使用并发技术可以开发出并行算法,充分利用多处理器的计算能力,避免硬件资源浪费。目前,在JAVA并发编程方面的论述系统且内容详实的技术资料不太多,Java...
### Java多线程学习笔记 #### 一、线程的基本概念 在计算机科学中,**线程**(Thread)是程序执行流的最小单位。一个标准的程序只能做一件事情,而通过多线程技术,可以让程序同时处理多个任务。在Java中,线程是...
Java 线程学习笔记 Java 线程创建有两种方法: 1. 继承 Thread 类,重写 run 方法:通过继承 Thread 类并重写 run 方法来创建线程,这种方法可以使线程具有自己的执行逻辑。 2. 实现 Runnable 接口:通过实现 ...
java基础:多线程学习笔记
Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现为Oracle公司的一部分)于1995年发布。...Java学习笔记涵盖了这些核心知识点,通过深入学习和实践,你可以逐步掌握Java编程,并应用于实际项目开发中。
Java多线程详解 在Java编程中,多线程是一种重要的技术,它使得程序能够同时执行多个任务,提高系统的效率和响应性。本教程将详细讲解Java中的多线程概念,包括线程的创建、状态、同步以及高级主题,旨在帮助初学者...
本学习笔记主要涵盖了Java的基础知识,包括面向对象、集合、IO流、多线程、反射与动态代理以及Java 8的新特性等方面,旨在帮助初学者或有经验的开发者巩固和提升Java编程技能。 1. 面向对象(OOP):Java的核心是...
张孝祥Java多线程与并发库高级应用学习笔记,很经典的学习多线程和并发的资料。张孝祥Java多线程讲义笔记由张孝祥亲自整理,很实用的。
### 张孝祥Java多线程与并发库高级应用笔记概览 #### 一、Java多线程技术的重要性与挑战 Java线程技术是软件工程领域不可或缺的一部分,尤其在底层编程、Android应用开发以及游戏开发中,其重要性不言而喻。然而,...