最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java任務(wù)調(diào)度的常見(jiàn)實(shí)現(xiàn)方法與比較詳解

 更新時(shí)間:2017年08月16日 10:19:49   作者:fancylovejava  
這篇文章主要介紹了Java任務(wù)調(diào)度的常見(jiàn)實(shí)現(xiàn)方法與比較,結(jié)合實(shí)例形式分析了Java任務(wù)調(diào)度的四種常見(jiàn)實(shí)現(xiàn)方法,使用區(qū)別及相關(guān)注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了Java任務(wù)調(diào)度的常見(jiàn)實(shí)現(xiàn)方法與比較。分享給大家供大家參考,具體如下:

簡(jiǎn)介: 綜觀目前的 Web 應(yīng)用,多數(shù)應(yīng)用都具備任務(wù)調(diào)度的功能。本文由淺入深介紹了幾種任務(wù)調(diào)度的 Java 實(shí)現(xiàn)方法,包括 Timer,Scheduler, Quartz 以及 JCron Tab,并對(duì)其優(yōu)缺點(diǎn)進(jìn)行比較,目的在于給需要開(kāi)發(fā)任務(wù)調(diào)度的程序員提供有價(jià)值的參考。

任務(wù)調(diào)度是指基于給定時(shí)間點(diǎn),給定時(shí)間間隔或者給定執(zhí)行次數(shù)自動(dòng)執(zhí)行任務(wù)。這里由淺入深介紹四種任務(wù)調(diào)度的 Java 實(shí)現(xiàn):

Timer
ScheduledExecutor
開(kāi)源工具包 Quartz
開(kāi)源工具包 JCronTab

此外,為結(jié)合實(shí)現(xiàn)復(fù)雜的任務(wù)調(diào)度,本文還將介紹 Calendar 的一些使用方法。

Timer

相信大家都已經(jīng)非常熟悉 java.util.Timer 了,它是最簡(jiǎn)單的一種實(shí)現(xiàn)任務(wù)調(diào)度的方法,下面給出一個(gè)具體的例子:

package com.ibm.scheduler;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest extends TimerTask {
 private String jobName = "";
 public TimerTest(String jobName) {
 super();
 this.jobName = jobName;
 }
 @Override
 public void run() {
 System.out.println("execute " + jobName);
 }
 public static void main(String[] args) {
 Timer timer = new Timer();
 long delay1 = 1 * 1000;
 long period1 = 1000;
 // 從現(xiàn)在開(kāi)始 1 秒鐘之后,每隔 1 秒鐘執(zhí)行一次 job1
 timer.schedule(new TimerTest("job1"), delay1, period1);
 long delay2 = 2 * 1000;
 long period2 = 2000;
 // 從現(xiàn)在開(kāi)始 2 秒鐘之后,每隔 2 秒鐘執(zhí)行一次 job2
 timer.schedule(new TimerTest("job2"), delay2, period2);
 }
}

Output:

execute job1
execute job1
execute job2
execute job1
execute job1
execute job2

使用 Timer 實(shí)現(xiàn)任務(wù)調(diào)度的核心類(lèi)是 Timer 和 TimerTask。其中 Timer 負(fù)責(zé)設(shè)定 TimerTask 的起始與間隔執(zhí)行時(shí)間。使用者只需要?jiǎng)?chuàng)建一個(gè) TimerTask 的繼承類(lèi),實(shí)現(xiàn)自己的 run 方法,然后將其丟給 Timer 去執(zhí)行即可。

Timer 的設(shè)計(jì)核心是一個(gè) TaskList 和一個(gè) TaskThread。Timer 將接收到的任務(wù)丟到自己的 TaskList 中,TaskList 按照 Task 的最初執(zhí)行時(shí)間進(jìn)行排序。TimerThread 在創(chuàng)建 Timer 時(shí)會(huì)啟動(dòng)成為一個(gè)守護(hù)線程。這個(gè)線程會(huì)輪詢(xún)所有任務(wù),找到一個(gè)最近要執(zhí)行的任務(wù),然后休眠,當(dāng)?shù)竭_(dá)最近要執(zhí)行任務(wù)的開(kāi)始時(shí)間點(diǎn),TimerThread 被喚醒并執(zhí)行該任務(wù)。之后 TimerThread 更新最近一個(gè)要執(zhí)行的任務(wù),繼續(xù)休眠。

Timer 的優(yōu)點(diǎn)在于簡(jiǎn)單易用,但由于所有任務(wù)都是由同一個(gè)線程來(lái)調(diào)度,因此所有任務(wù)都是串行執(zhí)行的,同一時(shí)間只能有一個(gè)任務(wù)在執(zhí)行,前一個(gè)任務(wù)的延遲或異常都將會(huì)影響到之后的任務(wù)。

ScheduledExecutor

鑒于 Timer 的上述缺陷,Java 5 推出了基于線程池設(shè)計(jì)的 ScheduledExecutor。其設(shè)計(jì)思想是,每一個(gè)被調(diào)度的任務(wù)都會(huì)由線程池中一個(gè)線程去執(zhí)行,因此任務(wù)是并發(fā)執(zhí)行的,相互之間不會(huì)受到干擾。需要注意的是,只有當(dāng)任務(wù)的執(zhí)行時(shí)間到來(lái)時(shí),ScheduedExecutor 才會(huì)真正啟動(dòng)一個(gè)線程,其余時(shí)間 ScheduledExecutor 都是在輪詢(xún)?nèi)蝿?wù)的狀態(tài)。

package com.ibm.scheduler;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorTest implements Runnable {
    private String jobName = "";
    public ScheduledExecutorTest(String jobName) {
        super();
        this.jobName = jobName;
    }
    @Override
    public void run() {
        System.out.println("execute " + jobName);
    }
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
        long initialDelay1 = 1;
        long period1 = 1;
    // 從現(xiàn)在開(kāi)始1秒鐘之后,每隔1秒鐘執(zhí)行一次job1
        service.scheduleAtFixedRate(
            new ScheduledExecutorTest("job1"), initialDelay1,
                period1, TimeUnit.SECONDS);
        long initialDelay2 = 1;
        long delay2 = 1;
    // 從現(xiàn)在開(kāi)始2秒鐘之后,每隔2秒鐘執(zhí)行一次job2
        service.scheduleWithFixedDelay(
            new ScheduledExecutorTest("job2"), initialDelay2,
                delay2, TimeUnit.SECONDS);
    }
}

Output:

execute job2
execute job1
execute job2
execute job1
execute job2
execute job1

清單 2 展示了 ScheduledExecutorService 中兩種最常用的調(diào)度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。ScheduleAtFixedRate 每次執(zhí)行時(shí)間為上一次任務(wù)開(kāi)始起向后推一個(gè)時(shí)間間隔,即每次執(zhí)行時(shí)間為 :initialDelay, initialDelay+period, initialDelay+2*period, …;ScheduleWithFixedDelay 每次執(zhí)行時(shí)間為上一次任務(wù)結(jié)束起向后推一個(gè)時(shí)間間隔,即每次執(zhí)行時(shí)間為:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。由此可見(jiàn),ScheduleAtFixedRate 是基于固定時(shí)間間隔進(jìn)行任務(wù)調(diào)度,ScheduleWithFixedDelay 取決于每次任務(wù)執(zhí)行的時(shí)間長(zhǎng)短,是基于不固定時(shí)間間隔進(jìn)行任務(wù)調(diào)度。

Timer 和 ScheduledExecutor 都僅能提供基于開(kāi)始時(shí)間與重復(fù)間隔的任務(wù)調(diào)度,不能勝任更加復(fù)雜的調(diào)度需求。比如,設(shè)置每星期二的 16:38:10 執(zhí)行任務(wù)。該功能使用 Timer 和 ScheduledExecutor 都不能直接實(shí)現(xiàn),但我們可以借助 Calendar 間接實(shí)現(xiàn)該功能。

package com.ibm.scheduler;
import java.util.Calendar;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExceutorTest2 extends TimerTask {
    private String jobName = "";
    public ScheduledExceutorTest2(String jobName) {
        super();
        this.jobName = jobName;
    }
    @Override
    public void run() {
        System.out.println("Date = "+new Date()+", execute " + jobName);
    }
    /**
     * 計(jì)算從當(dāng)前時(shí)間currentDate開(kāi)始,滿(mǎn)足條件dayOfWeek, hourOfDay,
     * minuteOfHour, secondOfMinite的最近時(shí)間
     * @return
     */
    public Calendar getEarliestDate(Calendar currentDate, int dayOfWeek,
            int hourOfDay, int minuteOfHour, int secondOfMinite) {
        //計(jì)算當(dāng)前時(shí)間的WEEK_OF_YEAR,DAY_OF_WEEK, HOUR_OF_DAY, MINUTE,SECOND等各個(gè)字段值
        int currentWeekOfYear = currentDate.get(Calendar.WEEK_OF_YEAR);
        int currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK);
        int currentHour = currentDate.get(Calendar.HOUR_OF_DAY);
        int currentMinute = currentDate.get(Calendar.MINUTE);
        int currentSecond = currentDate.get(Calendar.SECOND);
        //如果輸入條件中的dayOfWeek小于當(dāng)前日期的dayOfWeek,則WEEK_OF_YEAR需要推遲一周
        boolean weekLater = false;
        if (dayOfWeek < currentDayOfWeek) {
            weekLater = true;
        } else if (dayOfWeek == currentDayOfWeek) {
            //當(dāng)輸入條件與當(dāng)前日期的dayOfWeek相等時(shí),如果輸入條件中的
            //hourOfDay小于當(dāng)前日期的
            //currentHour,則WEEK_OF_YEAR需要推遲一周
            if (hourOfDay < currentHour) {
                weekLater = true;
            } else if (hourOfDay == currentHour) {
         //當(dāng)輸入條件與當(dāng)前日期的dayOfWeek, hourOfDay相等時(shí),
         //如果輸入條件中的minuteOfHour小于當(dāng)前日期的
                //currentMinute,則WEEK_OF_YEAR需要推遲一周
                if (minuteOfHour < currentMinute) {
                    weekLater = true;
                } else if (minuteOfHour == currentSecond) {
           //當(dāng)輸入條件與當(dāng)前日期的dayOfWeek, hourOfDay,
           //minuteOfHour相等時(shí),如果輸入條件中的
          //secondOfMinite小于當(dāng)前日期的currentSecond,
          //則WEEK_OF_YEAR需要推遲一周
                    if (secondOfMinite < currentSecond) {
                        weekLater = true;
                    }
                }
            }
        }
        if (weekLater) {
            //設(shè)置當(dāng)前日期中的WEEK_OF_YEAR為當(dāng)前周推遲一周
            currentDate.set(Calendar.WEEK_OF_YEAR, currentWeekOfYear + 1);
        }
        // 設(shè)置當(dāng)前日期中的DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND為輸入條件中的值。
        currentDate.set(Calendar.DAY_OF_WEEK, dayOfWeek);
        currentDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
        currentDate.set(Calendar.MINUTE, minuteOfHour);
        currentDate.set(Calendar.SECOND, secondOfMinite);
        return currentDate;
    }
    public static void main(String[] args) throws Exception {
        ScheduledExceutorTest2 test = new ScheduledExceutorTest2("job1");
        //獲取當(dāng)前時(shí)間
        Calendar currentDate = Calendar.getInstance();
        long currentDateLong = currentDate.getTime().getTime();
        System.out.println("Current Date = " + currentDate.getTime().toString());
        //計(jì)算滿(mǎn)足條件的最近一次執(zhí)行時(shí)間
        Calendar earliestDate = test
                .getEarliestDate(currentDate, 3, 16, 38, 10);
        long earliestDateLong = earliestDate.getTime().getTime();
        System.out.println("Earliest Date = "
                + earliestDate.getTime().toString());
        //計(jì)算從當(dāng)前時(shí)間到最近一次執(zhí)行時(shí)間的時(shí)間間隔
        long delay = earliestDateLong - currentDateLong;
        //計(jì)算執(zhí)行周期為一星期
        long period = 7 * 24 * 60 * 60 * 1000;
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
        //從現(xiàn)在開(kāi)始delay毫秒之后,每隔一星期執(zhí)行一次job1
        service.scheduleAtFixedRate(test, delay, period,
                TimeUnit.MILLISECONDS);
    }
}

Output:

Current Date = Wed Feb 02 17:32:01 CST 2011
Earliest Date = Tue Feb 8 16:38:10 CST 2011
Date = Tue Feb 8 16:38:10 CST 2011, execute job1
Date = Tue Feb 15 16:38:10 CST 2011, execute job1

清單 3 實(shí)現(xiàn)了每星期二 16:38:10 調(diào)度任務(wù)的功能。其核心在于根據(jù)當(dāng)前時(shí)間推算出最近一個(gè)星期二 16:38:10 的絕對(duì)時(shí)間,然后計(jì)算與當(dāng)前時(shí)間的時(shí)間差,作為調(diào)用 ScheduledExceutor 函數(shù)的參數(shù)。計(jì)算最近時(shí)間要用到 java.util.calendar 的功能。首先需要解釋 calendar 的一些設(shè)計(jì)思想。Calendar 有以下幾種唯一標(biāo)識(shí)一個(gè)日期的組合方式:

 YEAR + MONTH + DAY_OF_MONTH
 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 YEAR + DAY_OF_YEAR
 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR

上述組合分別加上 HOUR_OF_DAY + MINUTE + SECOND 即為一個(gè)完整的時(shí)間標(biāo)識(shí)。本例采用了最后一種組合方式。輸入為 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 以及當(dāng)前日期 , 輸出為一個(gè)滿(mǎn)足 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 并且距離當(dāng)前日期最近的未來(lái)日期。計(jì)算的原則是從輸入的 DAY_OF_WEEK 開(kāi)始比較,如果小于當(dāng)前日期的 DAY_OF_WEEK,則需要向 WEEK_OF_YEAR 進(jìn)一, 即將當(dāng)前日期中的 WEEK_OF_YEAR 加一并覆蓋舊值;如果等于當(dāng)前的 DAY_OF_WEEK, 則繼續(xù)比較 HOUR_OF_DAY;如果大于當(dāng)前的 DAY_OF_WEEK,則直接調(diào)用 java.util.calenda 的 calendar.set(field, value) 函數(shù)將當(dāng)前日期的 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 賦值為輸入值,依次類(lèi)推,直到比較至 SECOND。讀者可以根據(jù)輸入需求選擇不同的組合方式來(lái)計(jì)算最近執(zhí)行時(shí)間。

可以看出,用上述方法實(shí)現(xiàn)該任務(wù)調(diào)度比較麻煩,這就需要一個(gè)更加完善的任務(wù)調(diào)度框架來(lái)解決這些復(fù)雜的調(diào)度問(wèn)題。幸運(yùn)的是,開(kāi)源工具包 Quartz 與 JCronTab 提供了這方面強(qiáng)大的支持。

Quartz 可以滿(mǎn)足更多更復(fù)雜的調(diào)度需求,首先讓我們看看如何用 Quartz 實(shí)現(xiàn)每星期二 16:38 的調(diào)度安排:

package com.ibm.scheduler;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.helpers.TriggerUtils;
public class QuartzTest implements Job {
    @Override
    //該方法實(shí)現(xiàn)需要執(zhí)行的任務(wù)
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println("Generating report - "
                + arg0.getJobDetail().getFullName() + ", type ="
                + arg0.getJobDetail().getJobDataMap().get("type"));
        System.out.println(new Date().toString());
    }
    public static void main(String[] args) {
        try {
            // 創(chuàng)建一個(gè)Scheduler
            SchedulerFactory schedFact =
            new org.quartz.impl.StdSchedulerFactory();
            Scheduler sched = schedFact.getScheduler();
            sched.start();
            // 創(chuàng)建一個(gè)JobDetail,指明name,groupname,以及具體的Job類(lèi)名,
            //該Job負(fù)責(zé)定義需要執(zhí)行任務(wù)
            JobDetail jobDetail = new JobDetail("myJob", "myJobGroup",
                    QuartzTest.class);
            jobDetail.getJobDataMap().put("type", "FULL");
      // 創(chuàng)建一個(gè)每周觸發(fā)的Trigger,指明星期幾幾點(diǎn)幾分執(zhí)行
            Trigger trigger = TriggerUtils.makeWeeklyTrigger(3, 16, 38);
            trigger.setGroup("myTriggerGroup");
            // 從當(dāng)前時(shí)間的下一秒開(kāi)始執(zhí)行
            trigger.setStartTime(TriggerUtils.getEvenSecondDate(new Date()));
            // 指明trigger的name
            trigger.setName("myTrigger");
            // 用scheduler將JobDetail與Trigger關(guān)聯(lián)在一起,開(kāi)始調(diào)度任務(wù)
            sched.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Output:

Generating report - myJobGroup.myJob, type =FULL
Tue Feb 8 16:38:00 CST 2011
Generating report - myJobGroup.myJob, type =FULL
Tue Feb 15 16:38:00 CST 2011

清單 4 非常簡(jiǎn)潔地實(shí)現(xiàn)了一個(gè)上述復(fù)雜的任務(wù)調(diào)度。Quartz 設(shè)計(jì)的核心類(lèi)包括 Scheduler, Job 以及 Trigger。其中,Job 負(fù)責(zé)定義需要執(zhí)行的任務(wù),Trigger 負(fù)責(zé)設(shè)置調(diào)度策略,Scheduler 將二者組裝在一起,并觸發(fā)任務(wù)開(kāi)始執(zhí)行。

更多關(guān)于java相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java字符與字符串操作技巧總結(jié)》、《java日期與時(shí)間操作技巧匯總》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》和《Java緩存操作技巧匯總

希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Spring?Boot項(xiàng)目如何使用Maven打包并帶上依賴(lài)

    Spring?Boot項(xiàng)目如何使用Maven打包并帶上依賴(lài)

    在這篇博客中,介紹如何使用Maven將Spring?Boot項(xiàng)目及其依賴(lài)項(xiàng)打包成一個(gè)可執(zhí)行的jar文件。我們將使用Spring?Boot的spring-boot-maven-plugin插件來(lái)完成這個(gè)任務(wù),感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • java實(shí)現(xiàn)mongodb的數(shù)據(jù)庫(kù)連接池

    java實(shí)現(xiàn)mongodb的數(shù)據(jù)庫(kù)連接池

    這篇文章主要介紹了基于java實(shí)現(xiàn)mongodb的數(shù)據(jù)庫(kù)連接池,Java通過(guò)使用mongo-2.7.3.jar包實(shí)現(xiàn)mongodb連接池,感興趣的小伙伴們可以參考一下
    2015-12-12
  • 詳解@ConfigurationProperties如何裝載到Spring容器中

    詳解@ConfigurationProperties如何裝載到Spring容器中

    這篇文章主要為大家詳細(xì)介紹了@ConfigurationProperties該如何裝載到Spring容器中,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考一下
    2023-07-07
  • JAVACORE與HEAPDUMP生成方法

    JAVACORE與HEAPDUMP生成方法

    JavaCore文件主要保存的是Java應(yīng)用各線程在某一時(shí)刻的運(yùn)行的位置,即JVM執(zhí)行到哪一個(gè)類(lèi)、哪一個(gè)方法、哪一個(gè)行上,它是一個(gè)文本文件,打開(kāi)后可以看到每一個(gè)線程的執(zhí)行棧,以stack?trace的顯示,本文介紹JAVACORE與HEAPDUMP生成大法,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • 微信小程序 開(kāi)發(fā)中遇到問(wèn)題總結(jié)

    微信小程序 開(kāi)發(fā)中遇到問(wèn)題總結(jié)

    這篇文章主要介紹了微信小程序 開(kāi)發(fā)中遇到問(wèn)題總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java?深入理解創(chuàng)建型設(shè)計(jì)模式之原型模式

    Java?深入理解創(chuàng)建型設(shè)計(jì)模式之原型模式

    原型(Prototype)模式的定義如下:用一個(gè)已經(jīng)創(chuàng)建的實(shí)例作為原型,通過(guò)復(fù)制該原型對(duì)象來(lái)創(chuàng)建一個(gè)和原型相同或相似的新對(duì)象。在這里,原型實(shí)例指定了要?jiǎng)?chuàng)建的對(duì)象的種類(lèi)。用這種方式創(chuàng)建對(duì)象非常高效,根本無(wú)須知道對(duì)象創(chuàng)建的細(xì)節(jié)
    2022-02-02
  • java創(chuàng)建簡(jiǎn)易視頻播放器

    java創(chuàng)建簡(jiǎn)易視頻播放器

    這篇文章主要為大家詳細(xì)介紹了java創(chuàng)建簡(jiǎn)易視頻播放器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 在Action中以Struts2的方式輸出JSON數(shù)據(jù)的實(shí)例

    在Action中以Struts2的方式輸出JSON數(shù)據(jù)的實(shí)例

    下面小編就為大家?guī)?lái)一篇在Action中以Struts2的方式輸出JSON數(shù)據(jù)的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式

    PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式

    這篇文章主要介紹了PropertiesLoaderUtils 出現(xiàn)中文亂碼的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • java遍歷讀取xml文件內(nèi)容

    java遍歷讀取xml文件內(nèi)容

    這篇文章主要為大家介紹了java遍歷讀取xml文件內(nèi)容,感興趣的小伙伴們可以參考一下
    2016-01-01

最新評(píng)論

元氏县| 西乌珠穆沁旗| 青神县| 潞西市| 巴楚县| 景德镇市| 漳平市| 临西县| 门头沟区| 义马市| 延吉市| 松滋市| 阆中市| 靖州| 布拖县| 泸西县| 佛学| 双鸭山市| 凤城市| 辉南县| 抚顺县| 尚义县| 巴楚县| 弥勒县| 新宁县| 如东县| 房山区| 中山市| 自贡市| 琼中| 嘉黎县| 个旧市| 台北县| 湘潭县| 额尔古纳市| 大姚县| 静安区| 台湾省| 全南县| 开封县| 青龙|