【9159.com】该方法提供与此接口的 getDelay 方法一

作者: 编程  发布:2019-11-05

1、Thread.Sleep 是一路延迟,Task.Delay异步延迟。

职分概述

线程(Thread)是创办并发的底层工具,因而有早晚的局限性(不易获得再次来到值(必需透过创制分享域卡塔尔;卓殊的捕获和处理也麻烦;同一时间线程试行完成后不能够再度拉开该线程卡塔尔国,这几个局限性会减低品质同有的时候间影响并发性的贯彻(不轻巧组合超级小的产出操作达成异常的大的面世操作,会加多手工业同步管理(加锁,发送复信号卡塔尔的信赖,轻易现身难点卡塔尔。

线程池的(ThreadPool卡塔 尔(英语:State of Qatar)QueueUserWorkItem方法很容发起一遍异步的臆想范围操作。但以此能力相像持有众多范围,最大的主题素材是未曾内建的建制让您精晓操作在哪些时候做到,也平素不编写制定在操作完结时收获重回值。

Task类能够消除上述全数的主题材料。

任务(Task)表示叁个透过或不通过线程达成的产出操作,任务是可组合的,使用延续(continuation)可将它们串联在一同,它们得以使用线程池缩短运维延迟,可应用回调方法防止七个线程同一时候等待I/O密集操作。

 

这里提供二种在指准时间后运行线程的法子。一是通过java.util.concurrent.DelayQueue完结;二是经过java.util.concurrent.ScheduledThreadPoolExecutor达成。
1. java.util.concurrent.DelayQueue
类DelayQueue是三个无界梗塞队列,独有在延迟期满时技巧从当中提取元素。它肩负完结Delayed接口的实例作为成分。
<<interface>>Delayed.java

2、Thread.Sleep 会拥塞线程,Task.Delay不会。

底子任务(Task卡塔尔

微软在.NET 4.0 引入任务(Task)的定义。通过System.Threading.Tasks命名空间应用任务。它是在ThreadPool的底子上进展打包的。Task默许都以使用池化线程,它们都以后台线程,那表示主线程截至时其它职分也会随之告意气风发段落。

启航三个任务有三种方式,如以下示例:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Console.WriteLine("主线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
 6             int workerThreadsCount, completionPortThreadsCount;
 7             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
 8             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1}", workerThreadsCount, completionPortThreadsCount);
 9             //第一种:实例化方式Start启动
10             {
11                 Task task = new Task(() =>
12                 {
13                     Test("one-ok");
14                 });
15                 task.Start();
16             }
17             //第二种:通过Task类静态方法Run方式进行启动
18             {
19                 Task.Run(() =>
20                 {
21                     Test("two-ok");
22                 });
23             }
24             //第三种:通过TaskFactory的StartNew方法启动
25             {
26                 TaskFactory taskFactory = new TaskFactory();
27                 taskFactory.StartNew(() =>
28                 {
29                     Test("three-ok");
30                 });
31             }
32             //第四种:.通过Task.Factory进行启动
33             {
34                 Task taskStarNew = Task.Factory.StartNew(() =>
35                 {
36                     Test("four-ok");
37                 });
38             }
39             //第五种:通过Task对象的RunSynchronously方法启动(同步,由主线程执行,会卡主线程)
40             {
41                 Task taskRunSync = new Task(() =>
42                 {
43                     Console.WriteLine("线程Id:{0},执行方法:five-ok", Thread.CurrentThread.ManagedThreadId);
44                 });
45                 taskRunSync.RunSynchronously();
46             }
47             Thread.Sleep(1000);
48             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
49             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1}", workerThreadsCount, completionPortThreadsCount);
50             Console.ReadKey();
51         }
52         static void Test(string o)
53         {
54             Thread.Sleep(2000);
55             Console.WriteLine("线程Id:{0},执行方法:{1}", Thread.CurrentThread.ManagedThreadId, o);
56         }
57         /*
58          * 作者:Jonins
59          * 出处:http://www.cnblogs.com/jonins/
60          */
61     }

进行结果:

9159.com 1

上边示例中除去使用RunSynchronously方法运营的是合营任务(由启用的线程实行职责卡塔尔外,此外两种办法之中都由线程池内的劳力线程处理。

说明

1.其实Task.Factory类型本身正是TaskFactory(职责工厂卡塔尔,而Task.Run(在.NET4.5引进,4.0本子调用的是后人卡塔 尔(英语:State of Qatar)是Task.Factory.StartNew的简写法,是接班人的重载版本,更加灵活轻易些。

2.调用静态Run方法会自动创造Task对象并立即调用Start

3.如Task.Run等艺术运转职责并不曾调用Start,因为它制造的是“热”职责,相反“冷”任务的创设是通过Task构造函数。

 

package java.util.concurrent;
import java.util.*;
public interface Delayed extends Comparable<Delayed> {
    long getDelay(TimeUnit unit);
}

3、Thread.Sleep无法打消,Task.Delay能够。

返回值(Task<TResult>)&状态(Status)

Task有二个泛型子类Task<TResult>,它同意职分回到二个值。调用Task.Run,传入多个Func<Tresult>代理或同盟的Lambda表明式,然后查询Result属性获得结果。若是职分未达成,那么访谈Result属性会梗塞当前线程,直至职分成功

1     public static Task<TResult> Run<TResult>(Func<TResult> function);

而任务的Status品质可用以追踪职务的实行景况,如下所示:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> task = Task.Run(() =>
 6             {
 7                 int total = 0;
 8                 for (int i = 0; i <= 100; i++)
 9                 {
10                     total += i;
11                 }
12                 Thread.Sleep(2000);
13                 return total;
14             });
15             Console.WriteLine("任务状态:{0}",task.Status);
16             Thread.Sleep(1000);
17             Console.WriteLine("任务状态:{0}", task.Status);
18             int totalCount = task.Result;//如果任务没有完成,则阻塞
19             Console.WriteLine("任务状态:{0}", task.Status);
20             Console.WriteLine("总数为:{0}",totalCount);
21             Console.ReadKey();
22         }
23     }

奉行如下:

 9159.com 2

Reulst属性内部会调用Wait(等待卡塔尔;

任务的Status属性是一个TaskStatus枚举类型:

1  public TaskStatus Status { get; }

表达如下:

枚举值 说明
Canceled

任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;

或者在该任务开始执行之前,已向该任务的 CancellationToken 发出了信号。

Created 该任务已初始化,但尚未被计划。
Faulted 由于未处理异常的原因而完成的任务。
RanToCompletion 已完成执行的任务。
Running 任务正在运行,尚未完成。
WaitingForActivation 该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。
WaitingForChildrenToComplete 该任务已完成执行,正在隐式等待附加的子任务完成。
WaitingToRun 该任务已被计划执行,但尚未开始执行。

 

getDelay()重临与此对象相关的多余延迟时间,以给定的时间单位表示。此接口的得以达成必需定义三个compareTo 方法,该方式提供与此接口的 getDelay 方法相通的排序。

4. Task.Delay() 比 Thread.Sleep() 消耗更加多的能源,不过Task.Delay()可用于为艺术重回Task类型;或许依赖CancellationToken撤废标识动态撤消等待

职责会集重临值(WhenAll&WhenAny卡塔尔

 Task中有非常有利的对互相运营的天职集合获取再次来到值的秘籍,比方WhenAllWhenAny

DelayQueue队列的头顶是延迟期满后保存时间最长的 Delayed 成分。当一个要素的getDelay(提姆eUnit.NANOSECONDS) 方法重返三个低于等于 0 的值时,将生出到期。
2.规划带有时间推移特性的队列
类DelayedTasker维护四个DelayQueue<DelayedTask> queue,此中DelayedTask达成了Delayed接口,并由二个里头类定义。外界类和当中类都实现Runnable接口,对于外界类来讲,它的run方法是按定义的日子顺序抽取队列中的职责,而那么些职务即内部类的实例,内部类的run方法定义各个线程具体逻辑。

5. Task.Delay() 实质创立一个运转给准时期的任务, Thread.Sleep() 使当前线程休眠给如时期。

1.WhenAll

WhenAll:等候提供的有着 Task 对象完结实践进程(全体职分总体完了卡塔 尔(英语:State of Qatar)。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Task<int>> taskList = new List<Task<int>>();//声明一个任务集合
 6             TaskFactory taskFactory = new TaskFactory();
 7             for (int i = 0; i < 5; i++)
 8             {
 9                 int total = i;
10                 Task<int> task = taskFactory.StartNew(() => Test(total));
11                 taskList.Add(task);//将任务放进集合中
12             }
13             Console.WriteLine("主线程Id:{0},继续执行A.....", Thread.CurrentThread.ManagedThreadId);
14             Task<int[]> taskReulstList = Task.WhenAll(taskList);//创建一个任务,该任务将集合中的所有 Task 对象都完成时完成
15             for (int i = 0; i < taskReulstList.Result.Length; i++)//这里调用了Result,所以会阻塞线程,等待集合内所有任务全部完成
16             {
17                 Console.WriteLine("返回值:{0}", taskReulstList.Result[i]);//遍历任务集合内Task返回的值
18             }
19             Console.WriteLine("主线程Id:{0},继续执行B.....", Thread.CurrentThread.ManagedThreadId);
20             Console.ReadKey();
21         }
22         private static int Test(int o)
23         {
24             Console.WriteLine("线程Id:{0},Task执行成功,参数为:{1}", Thread.CurrentThread.ManagedThreadId, o);
25             Thread.Sleep(500 * o);
26             return o;
27         }
28     }

实施结果:

9159.com 3

那么些计划的真相是概念了四个怀不时间性子的线程职责列表,并且该列表能够是率性长度的。每回增添职分时钦赐运转时间就能够。
DelayedTasker.java

2.WhenAny

WhenAny:等待提供的任黄金时代 Task 对象达成实践进度(只要有叁个职勒令功卡塔 尔(英语:State of Qatar)。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Task<int>> taskList = new List<Task<int>>();//声明一个任务集合
 6             TaskFactory taskFactory = new TaskFactory();
 7             for (int i = 0; i < 5; i++)
 8             {
 9                 int total = i;
10                 Task<int> task = taskFactory.StartNew(() => Test(total));
11                 taskList.Add(task);//将任务放进集合中
12             }
13             Console.WriteLine("主线程Id:{0},继续执行A.....", Thread.CurrentThread.ManagedThreadId);
14             Task<Task<int>> taskReulstList = Task.WhenAny(taskList);//创建一个任务,该任务将在集合中的任意 Task 对象完成时完成
15             Console.WriteLine("返回值:{0}", taskReulstList.Result.Result);//得到任务集合内最先完成的任务的返回值
16             Console.WriteLine("主线程Id:{0},继续执行B.....", Thread.CurrentThread.ManagedThreadId);
17             Console.ReadKey();
18         }
19         private static int Test(int o)
20         {
21             Console.WriteLine("线程Id:{0},Task执行成功,参数为:{1}", Thread.CurrentThread.ManagedThreadId, o);
22             Thread.Sleep(500 * o);
23             return o;
24         }
25     }

奉行结果(这里重返值鲜明会是0,因为休眠最短卡塔尔:

9159.com 4

 

package com.zj.timedtask;

等待(Wait卡塔尔国&实践情势(TaskCreationOptions卡塔 尔(阿拉伯语:قطر‎

import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

1.职务等待(Wait卡塔尔国

调用职责的Wait主意可以卡住职责直至职分实现,形似于线程的join。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task task = Task.Run(() =>
 6             {
 7                 Console.WriteLine("线程执行Begin");
 8                 Thread.Sleep(2000);
 9                 Console.WriteLine("线程执行End");
10             });
11             Console.WriteLine("任务是否完成:{0}", task.IsCompleted);
12             task.Wait();//阻塞,直至任务完成
13             Console.WriteLine("任务是否完成:{0}", task.IsCompleted);
14             Console.ReadKey();
15         }
16     }

实施如下:

9159.com 5

注意

线程调用Wait方法时,系统一检查测线程要等待的Task是还是不是曾经起来实行。若是是线程则会卡住直到Task运维甘休结束。但万后生可畏Task还从未起来实行职分,系统也许(决定于TaskScheduler卡塔 尔(英语:State of Qatar)使用调用Wait的线程来施行Task,这种气象下调用Wait的线程不会梗塞,它会实践Task并马上回到。好处在于未有线程会被窒碍,所以降低了能源占用。不好的地点在于参与线程在调用Wait前早就获取了二个线程同步锁,而Task试图获取同二个锁,就能够形成死锁的线程。

import java.util.Collection;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

2.职分施行方式(TaskCreationOptions卡塔 尔(阿拉伯语:قطر‎

作者们明白为了创设叁个Task,要求调用构造函数并传递一个Action或Action<object>委托,假诺传递的是期望三个Object的办法,还必得向Task的构造函数穿都要传给操作的实参。还足以筛选向构造器传递一些TaskCreationOptions标识来决定Task的施行措施。

 TaskCreationOptions为枚举类型

枚举值 说明
None 默认。
PreferFairness 尽可能公平的方式安排任务,即先进先执行。
LongRunning 指定任务将是长时间运行的,会新建线程执行,不会使用池化线程。
AttachedToParent 指定将任务附加到任务层次结构中的某个父级
DenyChildAttach 任务试图和这个父任务连接将抛出一个InvalidOperationException
HideScheduler 强迫子任务使用默认调度而非父级任务调度

在暗中同意情形下,Task内部是运维在池化线程上,这种线程会极度符合施行短计算密集作业。借使要实施长窒碍操作,则要幸免接纳池化线程。

在池化线程上运维三个长职分难点非常小,但是如果要同期运营八个长职分(非常是会卡住的职责卡塔尔国,则会对品质发生影响。最棒应用:TaskCreationOptions.LongRunning。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             int workerThreadsCount, completionPortThreadsCount;
 6             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
 7             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1},主线程Id:{2}", workerThreadsCount, completionPortThreadsCount, Thread.CurrentThread.ManagedThreadId);
 8             Task task = Task.Factory.StartNew(() =>
 9             {
10                 Console.WriteLine("长任务执行,线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
11                 Thread.Sleep(2000);
12             }, TaskCreationOptions.LongRunning);
13             Thread.Sleep(1000);
14             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
15             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1},主线程Id:{2}", workerThreadsCount, completionPortThreadsCount, Thread.CurrentThread.ManagedThreadId);
16             Console.ReadKey();
17         }
18     }

施行结果如下:

9159.com 6

注意

即使使运维I/O密集任务,则足以选取TaskCompletionSource和异步函数(asynchronous functions卡塔尔,通过回调(三回九转卡塔尔国完结并发性,而是不通过线程完毕。

举个例子使运转总括密集性职分,则能够接纳多少个劳动者/花费者队列,调节这么些职责的面世数量,制止现身线程和进程堵塞的主题材料。

 

public class DelayedTasker implements Runnable {
    DelayQueue<DelayedTask> queue = new DelayQueue<DelayedTask>();

一而再(continuation卡塔尔国&一而再选项(TaskContinuationOptions卡塔 尔(英语:State of Qatar)

延续(continuation)会告诉任务在做到后继续推行上边的操作。一而再再而三平日由三个回调方法达成,它会在操作实现以往推行叁遍。给一个职务叠合三翻五次的点子有三种

    public void addTask(DelayedTask e) {
       queue.put(e);
    }

1.GetAwaiter

任务的章程GetAwaiter是Framework 4.5新添的,而C# 5.0的异步功能利用了这种办法,因而它超重大。给一个职责叠合延续如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> task = Task.Run(() =>
 6              {
 7                  int total = 0;
 8                  for (int i = 0; i <= 100; i++)
 9                  {
10                      total += i;
11                  }
12                  Thread.Sleep(2000);
13                  return total;
14              });
15             var awaiter = task.GetAwaiter();
16             awaiter.OnCompleted(() =>
17             {
18                 int result = awaiter.GetResult();//在延续中获取Task的执行结果
19                 Console.WriteLine(result);
20             });
21             Console.ReadKey();
22         }
23     }

实施结果肯定台会打字与印刷:5050。

调用GetAwaiter会再次回到贰个等待者(awaiter卡塔 尔(英语:State of Qatar)对象,它会让教导(antecedent卡塔尔职责在职分到位(或出错卡塔 尔(阿拉伯语:قطر‎之后实施三个代理。已经达成的任务也能够叠合一个后续,那事一而再一连会立马试行。

注意

1.等待者(awaiter卡塔 尔(阿拉伯语:قطر‎能够是自由对象,但必须要含有特定的多个点子和三个Boolean类型属性。

1   public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
2     {
3         public bool IsCompleted { get; }
4         public TResult GetResult();
5         public void OnCompleted(Action continuation);
6     }

2.指点任务现身谬误,那么当一连代码调用awaiter.GetResult()时就能再度抛出拾叁分。大家得以须求调用GetResult,而是一向访问初步职务的Result属性(task.Result)。

GetResult的获益是,当向导职责现身错误时,非常能够平昔抛出而不封装在AggregateException中。

3.万黄金时代现身一块上下文,那么会自动捕捉它,然后继续提交到这一个上下文中。在没有必要合作上下文的气象下平时不行使这种办法,使用ConfigureAwait代表它。它日常会使延续运行在引导职分所在的线程上,进而防止不供给的过载。

1    var awaiter = task.ConfigureAwait(false).GetAwaiter();

    public void removeTask() {
       queue.poll();
    }

2.ContinueWith

另黄金时代种附加三回九转的措施是调用任务的ContinueWith方法:

 1         static void Main(string[] args)
 2         {
 3             Task<int> task = Task.Run(() =>
 4             {
 5                 int total = 0;
 6                 for (int i = 0; i <= 100; i++)
 7                 {
 8                     total += i;
 9                 }
10                 Thread.Sleep(2000);
11                 return total;
12             });
13             task.ContinueWith(continuationAction =>
14             {
15                 int result = continuationAction.Result;
16                 Console.WriteLine(result);
17             });
18             Console.ReadKey();
19         }

ContinueWith作者会回来贰个Task,它丰富适用于增多越多的持续。然后风流浪漫旦职分现身错误,大家必得一贯处理AggregateException。

只要想让持续运转在统二个线程上,必得钦命 TaskContinuationOptions.ExecuteSynchronously;不然它会弹回线程池。ContinueWith特意适用于并行编制程序场景。

    public Collection<DelayedTask> getAllTasks() {
       return Collections.unmodifiableCollection(queue);
    }

3.一而再选项(TaskContinuationOptions卡塔 尔(英语:State of Qatar)

在使用ContinueWith时能够钦定任务的后续选项即TaskContinuationOptions,它的前两个枚举类型与事先说的TaskCreationOptions枚举提供的申明完全豆蔻梢头致,补充后续多少个枚举值:

枚举值 说明
LazyCancellation 除非先导任务完成,否则禁止延续任务完成(取消)。
NotOnRanToCompletion 指定不应在延续任务前面的任务已完成运行的情况下安排延续任务。
NotOnFaulted 指定不应在延续任务前面的任务引发了未处理异常的情况下安排延续任务。
NotOnCanceled 指定不应在延续任务前面的任务已取消的情况下安排延续任务。 
OnlyOnCanceled 指定只应在延续前面的任务已取消的情况下安排延续任务。
OnlyOnFaulted 指定只有在延续任务前面的任务引发了未处理异常的情况下才应安排延续任务。
OnlyOnRanToCompletion 指定只有在延续任务前面的任务引发了未处理异常的情况下才应安排延续任务。
ExecuteSynchronously 指定希望由先导任务的线程执行,先导任务完成后线程继续执行延续任务。

 

ExecuteSynchronously是指同步举办,三个职分都在同四个=线程大器晚成前黄金年代后的实行。

孔蒂nueWith结合TaskContinuationOptions使用的示范:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> task = Task.Run(() =>
 6             {
 7                 int total = 0;
 8                 for (int i = 0; i <= 100; i++)
 9                 {
10                     total += i;
11                 }
12                 if (total == 5050)
13                 {
14                     throw new Exception("错误");//这段代码可以注释或开启,用于测试
15                 }
16                 return total;
17             });
18             //指定先导任务无报错的延续任务
19             task.ContinueWith(continuationAction =>
20             {
21                 int result = continuationAction.Result;
22                 Console.WriteLine(result);
23             }, TaskContinuationOptions.NotOnFaulted);
24             //指定先导任务报错时的延续任务
25             task.ContinueWith(continuationAction =>
26             {
27                 foreach (Exception ex in continuationAction.Exception.InnerExceptions)//有关AggregateException异常处理后续讨论
28                 {
29                     Console.WriteLine(ex.Message);
30                 }
31             }, TaskContinuationOptions.OnlyOnFaulted);
32             Console.ReadKey();
33         }
34     }

施行结果会打印:报错,假设注释掉抛出拾壹分的代码则会打字与印刷5050。

 

    public int getTaskQuantity() {
       return queue.size();
    }

TaskCompletionSource

另意气风发种创立任务的不二秘诀是选取TaskCompletionSource。它同意制造多个职务,并能够职分分发给使用者,何况这个使用者能够应用该职分的其他成员。它的落到实处原理是透过叁个方可手动操作的“从属”任务,用于提醒操作达成或出错的小运。

TaskCompletionSource的确实意义是创制一个不绑定线程的天职(手动调控职务专业流,能够让你把创造职务和成功职分分别卡塔 尔(阿拉伯语:قطر‎

这种艺术特别切合I/O密集作业:能够行使全部任务的长处(它们能够转移重回值、非凡和继续卡塔尔国,但不会在操作执行时期梗塞线程。

例如,假如一个职务急需等待2秒,然后回到10,大家的方法会重回在叁个2秒后达成的职务,通过给职务叠合贰个三翻五次就可以在不打断任何线程的前提下打印这么些结果,如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var awaiter = Demo(2000).GetAwaiter();//得到任务通过延续输出返回值
 6             awaiter.OnCompleted(() =>
 7             {
 8                 Console.WriteLine(awaiter.GetResult());
 9             });
10             Console.WriteLine("主线程继续执行....");
11             Console.ReadKey();
12         }
13         static Task<int> Demo(int millis)
14         {
15             //创建一个任务完成源
16             TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>();
17             var timer = new System.Timers.Timer(millis) { AutoReset = false };
18             timer.Elapsed += delegate
19             {
20                 timer.Dispose(); taskCompletionSource.SetResult(10);//写入返回值
21             };
22             timer.Start();
23             return taskCompletionSource.Task;//返回任务
24         }
25     }

实行理并了结果:

9159.com 7

注意:借使频仍调用SetResult、SetException或SetCanceled,它们会抛出十二分,而TryXXX会重回false。

 

    public void run() {
       while (!queue.isEmpty())
           try {
              queue.take().run();
           } catch (InterruptedException e) {
              System.out.println("Interrupted");
           }
       System.out.println("Finished DelayedTask");
    }

职责废除(CancellationTokenSource卡塔 尔(阿拉伯语:قطر‎

黄金时代对处境下,后台任务大概运转不长日子,撤废义务就可怜有效了。.NET提供了生龙活虎种标准的天职裁撤机制可用以依据任务的异步格局

取消基于CancellationTokenSource类,该类可用来发送撤销央求。央求发送给援引CancellationToken类的天职,在那之中CancellationToken类与CancellationTokenSource类相关联。

应用示举个例子下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //构造函数 指定延迟2秒后自动取消任务
 6             CancellationTokenSource source = new CancellationTokenSource(2000);
 7             //注册一个任务取消后执行的委托
 8             source.Token.Register(() =>
 9             {
10                 Console.WriteLine("线程Id:{0} 任务被取消后的业务逻辑正在运行", Thread.CurrentThread.ManagedThreadId);
11             });
12             //启动任务,将取消标记源带入参数
13             Task.Run(() =>
14             {
15                 while (!source.IsCancellationRequested)//IsCancellationRequested为True时取消任务
16                 {
17                     Thread.Sleep(100);
18                     Console.WriteLine("线程Id:{0} 任务正在运行", Thread.CurrentThread.ManagedThreadId);
19                 }
20             }, source.Token);
21             //主线程挂起2秒后手动取消任务
22             {
23                 //Thread.Sleep(2000);
24                 //source.Cancel();//手动取消任务
25             }
26             //主线程不阻塞,2秒后自动取消任务
27             {
28                 source.CancelAfter(2000);
29             }
30             Console.ReadKey();
31         }
32     }

实践结果:

9159.com 8

根据Register措施绑定职责撤销后的嘱托

1   public CancellationTokenRegistration Register(Action callback);
2   public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext);
3   public CancellationTokenRegistration Register(Action<object> callback, object state);
4   public CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext);

手动废除义务Cancel方法

机动撤销义务

1.CancelAfter措施后面可以指引参数钦命延迟多少后时间收回职分。

1   public void CancelAfter(TimeSpan delay);
2   public void CancelAfter(int millisecondsDelay);

2.CancellationTokenSource构造函数能够辅导参数内定延迟多少时间后收回职务。

1   public CancellationTokenSource(TimeSpan delay);
2   public CancellationTokenSource(int millisecondsDelay);

职分绑定CancellationTokenSource对象,在Task源码中得以指引CancellationToken目的的启航职分措施都得以绑定CancellationTokenSource。

9159.com 9

 

    public static class DelayedTask implements Delayed, Runnable {
       private static int counter = 0;
       private final int id = counter++;
       private final int delta;
       private final long trigger;

异步等待 (Task.Delay卡塔尔

 异步等待特别实用,因而它形成Task类的叁个静态方法

 常用的利用方法有2种,如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //第1种
 6             {
 7                 Task.Delay(2000).ContinueWith((o) =>
 8                 {
 9                     Console.WriteLine("线程Id:{0},异步等待2秒后执行的逻辑", Thread.CurrentThread.ManagedThreadId);
10                 });
11             }
12             //第2种
13             {
14                 Task.Delay(3000).GetAwaiter().OnCompleted(() =>
15                 {
16                     Console.WriteLine("线程Id:{0},异步等待3秒后执行的逻辑", Thread.CurrentThread.ManagedThreadId);
17                 });
18             }
19             Console.WriteLine("主线程Id:{0},继续执行", Thread.CurrentThread.ManagedThreadId);
20             Console.ReadKey();
21         }
22     }

实行结果如下:

9159.com 10

Task.DelayThread.Sleep的异步版本。而它们的区分如下(引自 禅道 ):

1.Thread.Sleep 是同台延迟,Task.Delay异步延迟。

2.Thread.Sleep 会堵塞线程,Task.Delay不会。

3.Thread.Sleep不可能打消,Task.Delay可以。

4. Task.Delay() 比 Thread.Sleep() 消耗更加的多的财富,不过Task.Delay()可用于为方式重临Task类型;也许依照CancellationToken撤销标志动态裁撤等待。

5. Task.Delay() 实质创建贰个运作给依期期的任务, Thread.Sleep() 使当前线程休眠给定时期。

 

       public DelayedTask(int delayInSeconds) {
           delta = delayInSeconds;
           trigger = System.nanoTime() + NANOSECONDS.convert(delta, SECONDS);
       }

异常(AggregateException)

与线程分化,职分能够随即抛出极其。所以,如若职责中的代码抛出一个未管理分外,那么那几个可怜会自行传送到调用Wait()或Task<TResult>的Result属性的代码上。
任务的极度将会自行捕获并抛给调用者。为确定保证报告富有的十三分,CLRAV4会将卓殊封装在AggregateException容器中,该容器公开的InnerExceptions属性中带有全体捕获的那多少个,进而更合乎并行编制程序。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             try
 6             {
 7                 Task.Run(() =>
 8                 {
 9                     throw new Exception("错误");
10                 }).Wait();
11             }
12             catch (AggregateException axe)
13             {
14                 foreach (var item in axe.InnerExceptions)
15                 {
16                     Console.WriteLine(item.Message);
17                 }
18             }
19             Console.ReadKey();
20         }
21     }

上述示范调节台会显示:错误

注意

使用TaskIsFaultedIsCanceled属性,就足以不重复抛出特别而检查评定出错的职务。
1.IsFaulted和IsCanceled都回到False,表示并没错误发生。
2.IsCanceled为True,则任务抛出了OperationCanceledOperation(废除线程正在实施的操作时在线程中抛出的可怜)。
3.IsFaulted为True,则职责抛出另黄金年代种非常,而Exception属性包蕴了该错误。

       public long getDelay(TimeUnit unit) {
           return unit.convert(trigger - System.nanoTime(), NANOSECONDS);
       }

1.Flatten

当子职务抛出相当时,通过调用Flatten艺术,能够去掉任意档期的顺序的嵌套以简化分外管理。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var parent = Task.Factory.StartNew(() =>
 6             {
 7                 int[] numbers = { 0 };
 8                 var childFactory = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.None);
 9                 childFactory.StartNew(() => 10 / numbers[0]);//除零
10                 childFactory.StartNew(() => numbers[1]);//超出索引范围
11                 childFactory.StartNew(() => throw null);//空引用
12             });
13             try
14             {
15                 parent.Wait();
16             }
17             catch (AggregateException axe)
18             {
19                 foreach (var item in axe.Flatten().InnerExceptions)
20                 {
21                     Console.WriteLine(item.Message);
22                 }
23             }
24             Console.ReadKey();
25         }
26     }

9159.com 11

       public int compareTo(Delayed arg) {
           DelayedTask that = (DelayedTask) arg;
           if (trigger < that.trigger)
              return -1;
           if (trigger > that.trigger)
              return 1;
           return 0;
       }

2.Handle

 即使急需只捕获特定类型极度,同样重视抛其余体系的不得了,Handle情势为此提供了生机勃勃种飞速格局。

Handle选用叁个predicate(非凡断言卡塔 尔(阿拉伯语:قطر‎,并在每一种内部非常上运转此断言。

1 public void Handle(Func<Exception, bool> predicate);

假设断言再次回到True,它感到该非常是“已管理”,当有着非常过滤之后:

1.就算具备特别是已管理的,万分不会抛出。

2.比方存在至极未处理,就能够组织三个新的AggregateException对象来含有这几个极度并抛出。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var parent = Task.Factory.StartNew(() =>
 6             {
 7                 int[] numbers = { 0 };
 8                 var childFactory = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.None);
 9                 childFactory.StartNew(() => 10 / numbers[0]);//除零
10                 childFactory.StartNew(() => numbers[1]);//超出索引范围
11                 childFactory.StartNew(() => throw null);//空引用
12             });
13             try
14             {
15                 try
16                 {
17                     parent.Wait();
18                 }
19                 catch (AggregateException axe)
20                 {
21                     axe.Flatten().Handle(ex =>
22                     {
23                         if (ex is DivideByZeroException)
24                         {
25                             Console.WriteLine("除零-错误处理完毕");
26                             return true;
27                         }
28                         if (ex is IndexOutOfRangeException)
29                         {
30                             Console.WriteLine("超出索引范围-错误处理完毕");
31                             return true;
32                         }
33                         return false;//所有其它 异常重新抛出
34                     });
35 
36                 }
37             }
38             catch (AggregateException axe)
39             {
40                 foreach (var item in axe.InnerExceptions)//捕获重新抛出的异常
41                 {
42                     Console.WriteLine(item.Message);
43                 }
44             }
45             Console.ReadKey();
46         }
47     }

试行结果:

9159.com 12

 

       public void run() {
           //run all that you want to do
           System.out.println(this);
       }

 结语

1.async和await这三个首要字下篇记录。

2.任务调整器(TaskScheduler卡塔 尔(英语:State of Qatar)是Task之所以如此灵活的面目,大家常说Task是在ThreadPool上更晋级化的卷入,其实异常的大程度上归功于那个指标,思索下篇要不要讲一下,但实际笔者看的都胸口痛...

3.Task类包蕴众多的重载,最棒F12跳到Task内熟识下结构。

 

       public String toString() {
           return "[" + delta + "s]" + "Task" + id;
       }
    }

参照文献 

CLR via C#(第4版) Jeffrey Richter

C#高档编制程序(第10版卡塔 尔(英语:State of Qatar) C# 6 & .NET Core 1.0   Christian Nagel  

果壳中的C# C#5.0高贵指南  何塞普h Albahari

C#并发编制程序 优越实例  史蒂芬 Cleary

...

 

    public static void main(String[] args) {
       Random rand = new Random();
       ExecutorService exec = Executors.newCachedThreadPool();
       DelayedTasker tasker = new DelayedTasker();
       for (int i = 0; i < 10; i++)
           tasker.addTask(new DelayedTask(rand.nextInt(5)));
       exec.execute(tasker);
       exec.shutdown();
    }
}

结果:
[0s]Task 1
[0s]Task 2
[0s]Task 3
[1s]Task 6
[2s]Task 5
[3s]Task 8
[4s]Task 0
[4s]Task 4
[4s]Task 7
[4s]Task 9
Finished DelayedTask
3. java.util.concurrent.ScheduledThreadPoolExecutor
该类能够另行安插在给定的推移后运维任务(线程卡塔尔,或许准时(重复卡塔尔实施职务。在构造子中须求知道线程池的深浅。最重大的措施是:

[1] schedule

public ScheduledFuture<?> schedule(Runnable command, long delay,TimeUnit unit)

创设并奉行在给定延迟后启用的一遍性操作。
指定者:
-接口 ScheduledExecutorService 中的 schedule;
参数:
-command

  • 要实施的任务 ;
    9159.com,-delay
  • 从今后伊始延迟推行的年华 ;
    -unit
  • 延迟参数的岁月单位 ;
    返回:
    -表示挂起任务到位的 ScheduledFuture,而且其 get() 方法在完结后将回来 null。
     
    [2] scheduleAtFixedRate

public ScheduledFuture<?> scheduleAtFixedRate(
Runnable command,long initialDelay,long period,TimeUnit unit)

开创并实行叁个在给定发轫延迟后第壹回启用的期限操作,后续操作具备给定的周期;也便是就要initialDelay 后开首实施,然后在 initialDelay+period 后实施,接着在 initialDelay + 2 * period 后实施,由此及彼。借使职务的其他二个施行蒙受非常,则继续实践都会被撤回。不然,只好通过执行顺序的吊销或终止方法来终止该职务。假若此职分的其余二个奉行要开支比其周期越来越长的时间,则将推迟后续实施,但不会同不经常候施行。
指定者:
-接口 ScheduledExecutorService 中的 scheduleAtFixedRate;
参数:
-command

  • 要实施的天职 ;
    -initialDelay
  • 第3回实践的延迟时间 ;
    -period
  • 老是推行之间的周期 ;
    -unit
  • initialDelay 和 period 参数的时刻单位 ;
    返回:
    -表示挂起职务到位的 ScheduledFuture,并且其 get() 方法在废除后将抛出十分。
    4.企划带有的时候间推迟特性的线程推行者
    类ScheduleTasked关联三个ScheduledThreadPoolExcutor,能够钦定线程池的尺寸。通过schedule方法知情线程及推迟的光阴,通过shutdown方法关闭线程池。对于具体职责(线程卡塔 尔(阿拉伯语:قطر‎的逻辑具有自然的油滑(比较前一中设计,前风姿罗曼蒂克种设计必需优先定义线程的逻辑,但能够透过持续或点缀改进线程具体逻辑设计卡塔尔。
    ScheduleTasker.java

package com.zj.timedtask;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ScheduleTasker {
    private int corePoolSize = 10;
    ScheduledThreadPoolExecutor scheduler;

    public ScheduleTasker() {
       scheduler = new ScheduledThreadPoolExecutor(corePoolSize);
    }

    public ScheduleTasker(int quantity) {
       corePoolSize = quantity;
       scheduler = new ScheduledThreadPoolExecutor(corePoolSize);
    }

    public void schedule(Runnable event, long delay) {
       scheduler.schedule(event, delay, TimeUnit.SECONDS);
    }

    public void shutdown() {
       scheduler.shutdown();
    }

    public static void main(String[] args) {
       ScheduleTasker tasker = new ScheduleTasker();
       tasker.schedule(new Runnable() {
           public void run() {
              System.out.println("[1s]Task 1");
           }
       }, 1);
       tasker.schedule(new Runnable() {
           public void run() {
              System.out.println("[2s]Task 2");
           }
       }, 2);
       tasker.schedule(new Runnable() {
           public void run() {
              System.out.println("[4s]Task 3");
           }
       }, 4);
       tasker.schedule(new Runnable() {
           public void run() {
              System.out.println("[10s]Task 4");
           }
       }, 10);

       tasker.shutdown();
    }
}

结果:
[1s]Task 1
[2s]Task 2
[4s]Task 3
[10s]Task 4

本文由9159.com发布于编程,转载请注明出处:【9159.com】该方法提供与此接口的 getDelay 方法一

关键词: