一個普通的 Job 實現如下:
public class Job1 : IJob
{
public void Execute(IJobExecutionContext context)
{
Console.WriteLine(DateTime.Now + ": Job1" + m);
}
}
public class Program
{
static void Main(string[] args)
{
var props = new NameValueCollection();
//使用簡單線程池
props["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
//最大線程數
props["quartz.threadPool.threadCount"] = "10";
//線程優先級:正常
props["quartz.threadPool.threadPriority"] = "Normal";
//初始化調度器
IScheduler scheduler = new StdSchedulerFactory(props).GetScheduler();
//Cron 觸發器,每隔 1 秒觸發一次
ITrigger trig = TriggerBuilder.Create().WithCronSchedule("0/1 * * * * ?").Build();
//將作業 Job1 加入調度計劃中
scheduler.ScheduleJob(JobBuilder.Create<Job1>().Build(), trig);
//開始執行
scheduler.Start();
Console.ReadLine();
scheduler.Shutdown();
}
}
執行結果如下:可以看到,Job1 准確的每隔 1 秒執行一次

現在問題來了:如果 Job1 中的操作執行時間很長,超過了間隔時間 1 秒,會發生什麼情況?代碼如下:
public class Job1 : IJob
{
public void Execute(IJobExecutionContext context)
{
Console.WriteLine(DateTime.Now + ": Job1" + m);
//等待 5 秒
Thread.Sleep(5000);
}
}
執行結果如下:

我們會發現,Quartz 仍然會按照我們設定的每隔 1 秒觸發一次。
這是因為默認情況下,當Job執行時間超過間隔時間時,調度框架為了能讓任務按照我們預定的時間間隔執行,會馬上啟用新的線程執行任務。
若我們希望當前任務執行完之後再執行下一輪任務,也就是不要並發執行任務,該如何解決呢?
第一種方法:設置 quartz.threadPool.threadCount 最大線程數為 1。這樣到了第二次執行任務時,若當前還沒執行完,調度器想新開一個線程執行任務,但我們卻設置了最大線程數為 1 個(即:沒有足夠的線程提供給調度器),則調度器會等待當前任務執行完之後,再立即調度執行下一次任務。(注意:此方法僅適用於Quartz中僅有一個Job,如果有多個Job,會影響其他Job的執行)
第二種方法:在 Job 類的頭部加上 [DisallowConcurrentExecution],表示禁用並發執行。(推薦使用此方法)
//不允許此 Job 並發執行任務(禁止新開線程執行)
[DisallowConcurrentExecution]
public class Job1 : IJob
{
}