深入解讀Quartz任務(wù)調(diào)度器

深入解讀Quartz任務(wù)調(diào)度器

1.Quartz簡介

1.1.概要

Quartz是OpenSymphony提供的強(qiáng)大的開源任務(wù)調(diào)度框架。  
  官網(wǎng):http://www.quartz-scheduler.org
  純Java實(shí)現(xiàn),精細(xì)控制排程。

image

1.2.Quartz特點(diǎn)

  1. 強(qiáng)大的調(diào)度能力
  2. 靈活的應(yīng)用方式
  3. 強(qiáng)大的分布式和集群能力

1.3.Quartz設(shè)計(jì)模式

  • Builder模式
  • 組件模式
  • Factory模式
  • 鏈?zhǔn)綄懛?/li>

1.4.Quartz體系結(jié)構(gòu)

1.4.1.三大核心

  • 調(diào)度器
  • 任務(wù)
  • 觸發(fā)器
image

1.4.2.重要組成

1)任務(wù):

  • Job:表示一個(gè)工作,要執(zhí)行的具體內(nèi)容。此接口中只有一個(gè)方法。要?jiǎng)?chuàng)建一個(gè)任務(wù),必須得實(shí)現(xiàn)這個(gè)接口。該接口只有一個(gè)execute方法,任務(wù)每次被調(diào)用的時(shí)候都會(huì)執(zhí)行這個(gè)execute方法的邏輯,類似TimerTask的run方法,在里面編寫業(yè)務(wù)邏輯。

      public class TestJob implements Job {
          /**把要執(zhí)行的操作,寫在execute方法中  */
          @Override
          public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
              SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
              System.out.println("I can do something...");
              System.out.println(sdf.format(new Date()));
          }
      }
    

生命周期:在每次調(diào)度器執(zhí)行job時(shí),它在調(diào)用execute方法前會(huì)創(chuàng)建一個(gè)新的job實(shí)例,當(dāng)調(diào)用完成之后,關(guān)聯(lián)的job對象實(shí)例會(huì)被釋放,釋放的實(shí)例會(huì)被垃圾回收機(jī)制回收。

  • JobBuilder:可向任務(wù)傳遞數(shù)據(jù),通常情況下,我們使用它就可向任務(wù)類發(fā)送數(shù)據(jù)了,如有特別復(fù)雜的傳遞參數(shù),它提供了一個(gè)傳遞遞:JobDataMap對象的方法

      JobDetail jobDetail =  JobBuilder.newJob(TestJob.class).withIdentity("testJob","group1").build();
    
  • JobDetail:用來保存我們?nèi)蝿?wù)的詳細(xì)信息。一個(gè)JobDetail可以有多個(gè)Trigger,但是一個(gè)Trigger只能對應(yīng)一個(gè)JobDetail。下面是JobDetail的一些常用的屬性和含義:

image
  • JobStore:負(fù)責(zé)跟蹤所有你給scheduler的“工作數(shù)據(jù)”:jobs, triggers, calendars, 等。
    • RAMJobStore:是使用最簡單的也是最高效(依據(jù)CPU時(shí)間)的JobStore 。RAMJobStore 正如它名字描述的一樣,它保存數(shù)據(jù)在RAM。缺點(diǎn)是你的應(yīng)用結(jié)束之后所有的數(shù)據(jù)也丟失了--這意味著RAMJobStore 不具有保持job和trigger持久的能力。對于一些程序是可以接受的,甚至是期望的,但對于其他的程序可能是災(zāi)難性的。使用RAMJobStore配置Quartz:配置如下

        org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore 
      
    • JDBCJobStore:以JDBC的方式保存數(shù)據(jù)在數(shù)據(jù)庫中。它比RAMJobStore的配置復(fù)雜一點(diǎn),也沒有RAMJobStore快。然而,性能缺點(diǎn)不是糟透了,特別是如果你在數(shù)據(jù)庫表主鍵上建立了索引。在機(jī)器之間的LAN(在scheduler 和數(shù)據(jù)庫之間)合理的情況下,檢索和更新一個(gè)被觸發(fā)的Trigger花費(fèi)的時(shí)間少于10毫秒。幾乎適用于所有的數(shù)據(jù)庫,廣泛用于 Oracle。PostgreSQL, MySQL, MS SQLServer, HSQLDB, 和DB2。使用JDBCJobStore之前你必須首先創(chuàng)建一系列Quartz要使用的表。你可以發(fā)現(xiàn)表創(chuàng)建語句在Quartz發(fā)布目錄的 “docs/dbTables”下面。你需要確定你的應(yīng)用要使用的事務(wù)類型。如果你不想綁定調(diào)度命令(例如增加和移除Trigger)到其他的事務(wù),你可以使用JobStoreTX (最常用的選擇)作為你的Jobstore。如果你需要Quartz和其他的事務(wù)(例如在J2EE應(yīng)用服務(wù)器中)一起工作,你應(yīng)該使用JobStoreCMT ,Quartz 將讓應(yīng)用服務(wù)器容器管理這個(gè)事務(wù)。使用JobStoreTx配置Quartz:

        org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX  
        org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate  
        #配置表的前綴  
        org.quartz.jobStore.tablePrefix = QRTZ_  
        #使用JNDI數(shù)據(jù)源的時(shí)候,數(shù)據(jù)源的名字  
        org.quartz.jobStore.dataSource = myDS   
      
    • TerracottaJobStore:提供了一個(gè)方法:在不使用數(shù)據(jù)庫的情況下使它具有收縮性和強(qiáng)壯性。可以是集群的也可以是非集群的,在這兩種情況下為你的job數(shù)據(jù)提供了一個(gè)存儲機(jī)制用于應(yīng)用程序重啟之間持久,因?yàn)閿?shù)據(jù)是存儲在Terracotta服務(wù)器。它的性能比使用數(shù)據(jù)庫訪問JDBCJobStore好一點(diǎn)兒(大約是一個(gè)數(shù)量級),但是明顯比RAMJobStore慢。使用TerracottaJobStore配置Quartz:

        org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore  
        org.quartz.jobStore.tcConfigUrl = localhost:9510  
      
  • JobDataMap:中可以包含不限量的(序列化的)數(shù)據(jù)對象,在job實(shí)例執(zhí)行的時(shí)候,可以使用其中的數(shù)據(jù);JobDataMap是Java Map接口的一個(gè)實(shí)現(xiàn),額外增加了一些便于存取基本類型的數(shù)據(jù)的方法。
    • 存:

        JobDetail jobDetail =  JobBuilder.newJob(TestJob.class).withIdentity("testJob","group1").usingJobData("date1","存內(nèi)容").build(); 
      
    • 取:

        public class TestJob implements Job {
            /**把要執(zhí)行的操作,寫在execute方法中  */
            @Override
            public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
                JobKey key = jobExecutionContext.getJobDetail().getKey();
                JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
                String date1 = jobDataMap.getString("date1");
            }
        }
      

2)觸發(fā)器:用來觸發(fā)執(zhí)行Job

image

2.1)觸發(fā)器通用屬性:

  • Jobkey:表示job實(shí)例的標(biāo)識,觸發(fā)器被觸發(fā)時(shí),該指定的job實(shí)例會(huì)被執(zhí)行
  • StartTime:表示觸發(fā)器的時(shí)間表首次被觸發(fā)的時(shí)間,它的值類型為:java.util.Date
  • EndTime:指定觸發(fā)器的不再被觸發(fā)的時(shí)間,它的值類型為:java.util.Date

2.2)觸發(fā)器類型:

  • SimpleTrigger: 主要是針對一些相對簡單的時(shí)間觸發(fā)進(jìn)行配置使用,比如在指定的時(shí)間開始然后在一定的時(shí)間間隔之內(nèi)重復(fù)執(zhí)行一個(gè)Job,同時(shí)可以任意指定重復(fù)的次數(shù)。下面就是使用一個(gè)SimpleTrigger的例子:

      //創(chuàng)建觸發(fā)器 每3秒鐘執(zhí)行一次(無開始時(shí)間和結(jié)束時(shí)間)
      Trigger trigger = TriggerBuilder.newTrigger()
                  .withIdentity("trigger1", "group3")
                  .withSchedule(
                  SimpleScheduleBuilder.simpleSchedule()
                  .withIntervalInSeconds(3).repeatForever()).build();
      //創(chuàng)建觸發(fā)器 每3秒鐘執(zhí)行一次(有開始時(shí)間和結(jié)束時(shí)間)
      long now = new Date().getTime();
      Date start = new Date(now+6000);
      Date end = new Date(now+12000);
      //創(chuàng)建觸發(fā)器 每3秒鐘執(zhí)行一次
      Trigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity("trigger1", "group3")
                        .startAt(start)
                        .endAt(end)
                        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();
    

SimpleTrigger具有豐富的構(gòu)造函數(shù),根據(jù)業(yè)務(wù)需求構(gòu)造不同的構(gòu)造函數(shù)。

  • CronTrigger: 可以配置更復(fù)雜的觸發(fā)時(shí)刻表,基于日歷的作業(yè)觸發(fā)器,而不像SimpleTrigger那樣精確指定間隔時(shí)間,比SimpleTrigger更加常用。

Cron表達(dá)式:用于配置CronTrigger實(shí)例,是由7個(gè)表達(dá)式組成的字符串,描述了時(shí)間表的詳細(xì)信息。
  格式為:[秒][分][時(shí)][日][月][周][年]
  Cron表達(dá)式特殊字符意義對應(yīng)表:
  

image

  通配符說明:
  
image

  Cron表達(dá)式例子:
  
image

    TriggerBuilder.newTrigger().withIdentity("trigger2","group2")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 ? * 6L *")).build();

Cron表達(dá)式小技巧:
  1. ‘L’和‘W’可以一起組合使用
  2. 周字段英文字母不區(qū)分大小寫即MOM與mom相同
  3. 利用工具,在線生成cron表達(dá)式:http://cron.qqe2.com/

  • NthIncludedDayTrigger:是 Quartz 開發(fā)團(tuán)隊(duì)最新加入到框架中的一個(gè) Trigger。它設(shè)計(jì)用于在每一間隔類型的第幾天執(zhí)行 Job。例如,你要在每個(gè)月的 15 號執(zhí)行開票的 Job,用 NthIncludedDayTrigger就再合適不過了。

      NthIncludedDayTrigger trigger = new NthIncludedDayTrigger("NthIncludedDayTrigger",Scheduler.DEFAULT_GROUP);
                  trigger.setN(15);
                  trigger.setIntervalType(NthIncludedDayTrigger.INTERVAL_TYPE_MONTHLY);
    

3)調(diào)度器Scheduler
  代表一個(gè)Quartz的獨(dú)立運(yùn)行容器,Trigger和JobDetail可以注冊到Scheduler中,兩者在Scheduler中擁有各自的組及名稱,組及名稱是Scheduler查找定位容器中某一對象的依據(jù),Trigger的組及名稱必須唯一,JobDetail的組和名稱也必須唯一(但可以和Trigger的組和名稱相同,因?yàn)樗鼈兪遣煌愋偷模cheduler定義了多個(gè)接口方法,允許外部通過組及名稱訪問和控制容器中Trigger和JobDetail。
  Scheduler可以將Trigger綁定到某一JobDetail中,這樣當(dāng)Trigger觸發(fā)時(shí),對應(yīng)的Job就被執(zhí)行。一個(gè)Job可以對應(yīng)多個(gè)Trigger,但一個(gè)Trigger只能對應(yīng)一個(gè)Job。
  可以通過SchedulerFactory創(chuàng)建一個(gè)Scheduler實(shí)例。Scheduler擁有一個(gè)SchedulerContext,它類似于ServletContext,保存著Scheduler上下文信息,Job和Trigger都可以訪問SchedulerContext內(nèi)的信息。SchedulerContext內(nèi)部通過一個(gè)Map,以鍵值對的方式維護(hù)這些上下文數(shù)據(jù),SchedulerContext為保存和獲取數(shù)據(jù)提供了多個(gè)put()和getXxx()的方法。可以通過Scheduler# getContext()獲取對應(yīng)的SchedulerContext實(shí)例;

    SchedulerFactory schedulerfactory=new StdSchedulerFactory();
    Scheduler scheduler = schedulerfactory.getScheduler();

    DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
    try {
        Scheduler scheduler = factory.getScheduler();
    } catch (SchedulerException e) {
        e.printStackTrace();
    }

4)SchedulerFactory:

  • 使用一組參數(shù)(java.util.Properties)來創(chuàng)建和出書啊Quartz調(diào)度器
  • 配置參數(shù)一般存儲在quartz.properties中
  • 調(diào)用getScheduler方法就能創(chuàng)建和初始化調(diào)度器

5)quartz.properties:
Quartz-Job的quartz.properties配置文件說明,此文件在quartz的jar包有,可直接拿過來使用不過只有基本的幾個(gè)配置 自己可根據(jù)需要進(jìn)行擴(kuò)充;另外如果項(xiàng)目中沒有對該配置文件重寫,則Quartz會(huì)加載自己jar包中的quartz.properties文件。

    # Default Properties file for use by StdSchedulerFactory  
    # to create a Quartz Scheduler Instance, if a different  
    # properties file is not explicitly specified.  
    #  
    # ===========================================================================  
    # Configure Main Scheduler Properties 調(diào)度器屬性  
    # ===========================================================================  
    org.quartz.scheduler.instanceName: DefaultQuartzScheduler  
    #org.quartz.scheduler.instanceid:AUTO  
    org.quartz.scheduler.rmi.export: false  
    org.quartz.scheduler.rmi.proxy: false  
    org.quartz.scheduler.wrapJobExecutionInUserTransaction: false  
    # ===========================================================================    
    # Configure ThreadPool 線程池屬性    
    # ===========================================================================  
    #線程池的實(shí)現(xiàn)類(一般使用SimpleThreadPool即可滿足幾乎所有用戶的需求)  
    org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool  
    #指定線程數(shù),至少為1(無默認(rèn)值)(一般設(shè)置為1-100直接的整數(shù)合適)  
    org.quartz.threadPool.threadCount: 10  
    #設(shè)置線程的優(yōu)先級(最大為java.lang.Thread.MAX_PRIORITY 10,最小為Thread.MIN_PRIORITY 1,默認(rèn)為5)  
    org.quartz.threadPool.threadPriority: 5  
    #設(shè)置SimpleThreadPool的一些屬性  
    #設(shè)置是否為守護(hù)線程  
    #org.quartz.threadpool.makethreadsdaemons = false  
    #org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true  
    #org.quartz.threadpool.threadsinheritgroupofinitializingthread=false  
    #線程前綴默認(rèn)值是:[Scheduler Name]_Worker  
    #org.quartz.threadpool.threadnameprefix=swhJobThead;  
    # 配置全局監(jiān)聽(TriggerListener,JobListener) 則應(yīng)用程序可以接收和執(zhí)行 預(yù)定的事件通知  
    # ===========================================================================  
    # Configuring a Global TriggerListener 配置全局的Trigger監(jiān)聽器  
    # MyTriggerListenerClass 類必須有一個(gè)無參數(shù)的構(gòu)造函數(shù),和 屬性的set方法,目前2.2.x只支持原始數(shù)據(jù)類型的值(包括字符串)  
    # ===========================================================================  
    #org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass  
    #org.quartz.triggerListener.NAME.propName = propValue  
    #org.quartz.triggerListener.NAME.prop2Name = prop2Value  
    # ===========================================================================  
    # Configuring a Global JobListener 配置全局的Job監(jiān)聽器  
    # MyJobListenerClass 類必須有一個(gè)無參數(shù)的構(gòu)造函數(shù),和 屬性的set方法,目前2.2.x只支持原始數(shù)據(jù)類型的值(包括字符串)  
    # ===========================================================================  
    #org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass  
    #org.quartz.jobListener.NAME.propName = propValue  
    #org.quartz.jobListener.NAME.prop2Name = prop2Value  
    # ===========================================================================    
    # Configure JobStore 存儲調(diào)度信息(工作,觸發(fā)器和日歷等)  
    # ===========================================================================  
    # 信息保存時(shí)間 默認(rèn)值60秒  
    org.quartz.jobStore.misfireThreshold: 60000  
    #保存job和Trigger的狀態(tài)信息到內(nèi)存中的類  
    org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore  
    # ===========================================================================    
    # Configure SchedulerPlugins 插件屬性 配置  
    # ===========================================================================  
    # 自定義插件    
    #org.quartz.plugin.NAME.class = com.swh.MyPluginClass  
    #org.quartz.plugin.NAME.propName = propValue  
    #org.quartz.plugin.NAME.prop2Name = prop2Value  
    #配置trigger執(zhí)行歷史日志(可以看到類的文檔和參數(shù)列表)  
    org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin    
    org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}    
    org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}    
    #配置job調(diào)度插件  quartz_jobs(jobs and triggers內(nèi)容)的XML文檔    
    #加載 Job 和 Trigger 信息的類   (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin)  
    org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin  
    #指定存放調(diào)度器(Job 和 Trigger)信息的xml文件,默認(rèn)是classpath下quartz_jobs.xml  
    org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml    
    #org.quartz.plugin.jobInitializer.overWriteExistingJobs = false    
    org.quartz.plugin.jobInitializer.failOnFileNotFound = true    
    #自動(dòng)掃描任務(wù)單并發(fā)現(xiàn)改動(dòng)的時(shí)間間隔,單位為秒  
    org.quartz.plugin.jobInitializer.scanInterval = 10  
    #覆蓋任務(wù)調(diào)度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情況  
    org.quartz.plugin.jobInitializer.wrapInUserTransaction = false  
    # ===========================================================================    
    # Sample configuration of ShutdownHookPlugin  ShutdownHookPlugin插件的配置樣例  
    # ===========================================================================  
    #org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin  
    #org.quartz.plugin.shutdownhook.cleanShutdown = true  
    #  
    # Configure RMI Settings 遠(yuǎn)程服務(wù)調(diào)用配置  
    #  
    #如果你想quartz-scheduler出口本身通過RMI作為服務(wù)器,然后設(shè)置“出口”標(biāo)志true(默認(rèn)值為false)。  
    #org.quartz.scheduler.rmi.export = false  
    #主機(jī)上rmi注冊表(默認(rèn)值localhost)  
    #org.quartz.scheduler.rmi.registryhost = localhost  
    #注冊監(jiān)聽端口號(默認(rèn)值1099)  
    #org.quartz.scheduler.rmi.registryport = 1099  
    #創(chuàng)建rmi注冊,false/never:如果你已經(jīng)有一個(gè)在運(yùn)行或不想進(jìn)行創(chuàng)建注冊  
    # true/as_needed:第一次嘗試使用現(xiàn)有的注冊,然后再回來進(jìn)行創(chuàng)建  
    # always:先進(jìn)行創(chuàng)建一個(gè)注冊,然后再使用回來使用注冊  
    #org.quartz.scheduler.rmi.createregistry = never  
    #Quartz Scheduler服務(wù)端端口,默認(rèn)是隨機(jī)分配RMI注冊表  
    #org.quartz.scheduler.rmi.serverport = 1098  
    #true:鏈接遠(yuǎn)程服務(wù)調(diào)度(客戶端),這個(gè)也要指定registryhost和registryport,默認(rèn)為false  
    # 如果export和proxy同時(shí)指定為true,則export的設(shè)置將被忽略  
    #org.quartz.scheduler.rmi.proxy = false  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,510評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內(nèi)容