java之并发&线程(三)
JavaSE5提供了一个方便操作线程的方式。
下面是一个run方法。
在使用时可以用executor。代替了你调用start。
execute(Runnable)方法runnable 必须不为空。Runnable为空是nullpointexception。
当无法执行runnable时rejectedExecutionException。
Tips:executor正在关闭并且不想接受新的任务时,没有足够的空间存储这一任务时会抛rejected
下面看一下这个Executors的源码
这个类的目的就是创建执行器。产生executorService.
有多种创建方式。最常用的是newCachedThreadPool(); newFixedThreadPool(); newSingleThreadExecutor();这三种
newCachedThreadPool:缓存型池子通常用于执行一些生存期很短的异步型任务。 大部分用这个。
newFixedThreadPool:FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器
任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程(新的任务出现)要建立,只能放在另外的队列中等待,直到当前的某个任务执行完毕。
newSingleThreadExecutor:相当于newFixedThreadPool(0);
以上的介绍是没有针对void run();这个是runnable异步任务的执行结果,这个就是任务的执行是没有返回值的。
对于有返回值的任务需要调用executorService的submit方法来实现。而玩的是callable而不是runnable
callable这个东西也是jdk1.5提出来的。
下面是使用的例子。可以看到我得到了这个任务的返回结果,这个返回结果的泛型是我自定义的;submit的执行结果是future.通过get方法可以得到返回结果。根据future通过它我们可以跟踪到异步任务的执行和停止。
1 . cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
2.isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
3.isDone方法表示任务是否已经完成,若任务完成,则返回true;
4.get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
5.get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null.
Get会产生阻塞。future.get 等线程执行完在执行其他线程
shutdown() shutdownNow()区别
void shutdown方法发起一个关闭请求,已提交的任务会执行,但不会接受新的任务请求了。 只是关闭了提交通道,用submit()是无效的
List<Runnable> shutdownNow方法,这个方法会停掉所有执行中的任务,取消等待中的任务,返回等待执行的任务 的list
方法不会等待执行中的任务停止。
awaitTermination方法会阻止开启新的任务并且尝试停止当前正在执行的线程,一旦调用该方法,线程池中将没有**的任务,没有等待执行的任务,也没有新任务提交。没有任务执行的ExecutorService将会被回收。
boolean isShutdown();
如果线程池停止完成返回true
isShutDown当调用shutdown()或shutdownNow()方法后返回为true。
isTerminated当调用shutdown()方法后,并且所有提交的任务完成后返回为true;
isTerminated当调用shutdownNow()方法后,成功停止后返回为true;
如果线程池任务正常完成,都为false
Boolean awaitTermination(long timeOut, TimeUnit unit)
当前线程阻塞,直到等所有已提交的任务(包括正在跑的和队列中等待的)执行完或者等超时时间到或者线程被中断(抛出InterruptedException)
executor终止返回true ,终止之前超时返回false
Submit
1.方法submit扩展了Executor.execute(Runnable) 方法, 创建并返回一个 Future 结果,这个Future可以取消任务的执行或者等待完成得到返回值。
方法invokeAny and invokeAll 可以执行一组任务,等待至少一个任务或者多个任务完成(ExecutorCompletionService扩展了这些方法的实现)
如果你想要阻塞当前线程并知道执行完成返回结果,那么你可以这样做: result = exec.submit(callableInstance).get();
2.submit方法有重载的方法入参为runnable。这个就是future的结果是null、
3.<T> Future<T> submit(Runnable task, T result);
提交一个Runnable任务执行,返回一个Future做为任务task的代理,Future.get()方法在执行成功后可以返回结果。
Runnable task 提交的任务 T results 执行的结果
4.入参为callable的返回的future就是正常你设计的泛型。
T InvokeAny()
List<Callable<?>> task;(有任务成功完成执行就返回结果,全部异常就抛异常,未完成执行的任务会被取消)
如果提交的任务列表中,没有1个正常完成的任务,那么调用invokeAny会抛异常,究竟抛的是哪儿个任务的异常,无关紧要。
invokeAny()和任务的提交顺序无关,只是返回最早正常执行完成的任务。
如果在超时之前,所有任务已经都是异常终止,那就没有必要在等下去了,如果超时之后,仍然有正在运行或等待运行的任务,会TimeOut.
invokeAny()返回最先正常完成(without throwing exception)的任务直接结果;
List<Callable<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit);
就是执行任务列表中的所有任务,并返回与每个任务对应的Futue。也就是说,任务彼此之间不会相互影响,可以通过future跟踪每一个任务的执行情况,比如是否被取消,是正常完成,还是异常完成。
调用invokeAll的线程会阻塞,直到tasks全部执行完成(正常完成/异常退出)
invokeAll是一个阻塞方法,会等待任务列表中的所有任务都执行完成。不管任务是正常完成,还是异常终止,Future.isDone()始终返回true。通过Future.isCanceled()可以判断任务是否在执行的过程中被取消。通过Future.get()可以获取任务的返回结果,或者是任务在执行中抛出的异常。
对于有TimeUnit参数的重载方法,给定的超时期满,还没有完成的任务会被取消。
一旦ExecutorService.invokeAll()方法产生了异常,线程池中还没有完成的任务会被取消执行。
线程的异常处理
正常情况下我们是无法捕获到异常的。
下面这么玩可以捕获到异常。一环套一环。
TimeUnit 时间类
TimeUnit.SECONDS.toMillis(44) 将34秒转换成毫秒 34000.
TimeUnit.MINUTES.sleep(1); sleep一分钟。
还有纳秒,微秒,毫秒,秒,(分钟),小时,日。 Ordinal
将参数颗粒度时间转换为指定颗粒度时间
// 将48小时转换为天数
System.out.println(TimeUnit.DAYS.convert(48, TimeUnit.HOURS));
int compareTo(Enum) TimeUnit.
// 对指定线程休眠2秒
void TimeUnit.SECONDS.timedJoin(Thread.currentThread(), 2);
TimeUnit.MINUTES.compareTo(TimeUnit.DAYS); //返回ordinal差值
TimeUnit.values(); //返回所有枚举的数组
void timedWait(Object obj, long timeout); 锁住(方法)这样对象才顺序访问。
TimeUnit TimeUnit(name); 返回指定枚举名称的枚举。
一个定时器框架
定时器框架。延迟2000毫秒后执行一次。仅一次。
timer.schedule(task,delay,period);
timer() 的任务执行线程是非守护线程。
Timer(Boolean isDaemon)创建一个可能会以守护线程运行的定时器。
Timer(string name);创建一个拥有指定名称的定时器。Name不给空指针异常。
Timer(name,isDaemon);结合两者的属性。
一个定时器对象可以调用多个task .
cancel 终止定时器,丢弃所有当前调度的定时器任务。这个方法不会干预当前正在执行的定时器任务。
Schedule(timerTask,date) date是在某个时间点执行定时任务。负数抛异常,过去的时间直接执行。
Schedule(timerTask,date,period) 固定时间间隔重复。
Schedule(timerTask,deloy)延迟多少毫秒。
Schedule(timerTask,deloy,period)延迟,在固定间隔触发。
Timer,timertask 的cancel方法区别:timer的cancel会终止定时器并放弃当前任意被调度的定时任务。TimerTask 的cancel仅仅会取消正在调用的定时任务。
参考:《java编程思想》《java线程与并发编程实践》