聯(lián)系我們 - 廣告服務(wù) - 聯(lián)系電話:
您的當(dāng)前位置: > 關(guān)注 > > 正文

速讀:程序、進(jìn)程和線程——多線程的創(chuàng)建方法

來(lái)源:CSDN 時(shí)間:2023-03-07 11:40:09

目錄


【資料圖】

程序、進(jìn)程和線程的概念

多線程的優(yōu)點(diǎn)

Thread類關(guān)于多線程的創(chuàng)建

Thread類的相關(guān)方法

線程的調(diào)度

線程的五種狀態(tài)

線程的同步

總結(jié)同步方法

衍生內(nèi)容————單例設(shè)計(jì)模式

死鎖問(wèn)題

鎖的概念

sleep()和wait()的異同

首先要明確幾個(gè)概念

程序、進(jìn)程和線程的概念

程序:完成特定任務(wù),用某種特殊的語(yǔ)言編寫的一組指令的集合

進(jìn)程:是執(zhí)行路徑,一個(gè)進(jìn)程同一時(shí)間并行或者正在運(yùn)行的程序

線程:是執(zhí)行路徑,一個(gè)進(jìn)程同一時(shí)間并行或者執(zhí)行多個(gè)進(jìn)程,就是多線程

注:進(jìn)程中也有可能有多個(gè)線程

CPU也分為多核CPU和單核CPU

單核CPU:實(shí)際上進(jìn)行的是某種意義上的假CPU,一個(gè)CPU同時(shí)做好多事,如果一個(gè)沒(méi)有準(zhǔn)備好,就先將該事件掛起,去進(jìn)行別的,可以用一張圖來(lái)表示

多核CPU(取決與主頻來(lái)利用哪個(gè)):多核CPU就相當(dāng)于多個(gè)單核CPU工作

同時(shí)也要解釋兩個(gè)詞的含義

并行:多個(gè)CPU任務(wù)一起進(jìn)行

并發(fā):一個(gè)CPU做多個(gè)任務(wù)

注:并發(fā)只是看上去“同時(shí)”,但是實(shí)際上只是在CPU上進(jìn)行高速的切換任務(wù),以至于僅僅是看上去是同時(shí),并行才是真正意義上的同時(shí)

多線程的優(yōu)點(diǎn)

1、提高應(yīng)用程序的響應(yīng)

2、提高CPU的利用率

3、改善程序結(jié)構(gòu),每個(gè)線程獨(dú)立運(yùn)行,互不干擾,便于修改

提到多線程,就不得不提一個(gè)特殊的類

Thread類關(guān)于多線程的創(chuàng)建

方法一:

1、創(chuàng)建一個(gè)繼承于Thread類的子類

2、重寫Thread類中的run()

3、創(chuàng)建Thread類子類的對(duì)象(要在主線程上創(chuàng)建)、

4、通過(guò)對(duì)象去調(diào)用start()

想要?jiǎng)?chuàng)建一個(gè)多線程的代碼如下

//主函數(shù)中的體現(xiàn)為//1、創(chuàng)建了繼承Thread的子類//在繼承Thread中的表現(xiàn)為public class ExtendsThread extends Thread {    @Override    //2、此處為標(biāo)準(zhǔn)的對(duì)于run()函數(shù)重寫    //對(duì)run()函數(shù)的重寫就相當(dāng)于對(duì)于這一條線程中你想做的所有任務(wù)    public void run() {        super.run();        for(int i=0;i<=20;i++)        {            System.out.println(i);        }    }}public class ThreadTest {    public static void main(String[]args) {        //3、創(chuàng)建了繼承Thread子類的對(duì)象        Thread et=new ExtendsThread();        //4、通過(guò)對(duì)象調(diào)用了start()        et.start();        //調(diào)用start()之后就開啟多線程    }}

此處需要注意的是

1、run方法的重寫:將這個(gè)線程要執(zhí)行的所有操作全部都聲明在run方法中

2、et.run()也能在主函數(shù)中直接調(diào)用,也能完整的執(zhí)行在run方法中的指令,但是不能體現(xiàn)多線程,就僅僅是將指令完成,et.run()就僅僅只是調(diào)用方法看

3、不能夠讓已經(jīng)start()的線程再去重啟線程

4、可以創(chuàng)建多個(gè)對(duì)于ExtendsThread的對(duì)象,此時(shí)這個(gè)對(duì)象可以再次開始start(),相當(dāng)于多開了一個(gè)線程,只不過(guò)執(zhí)行的是相同內(nèi)容

5、匿名子類與匿名對(duì)象同樣適用

public class ThreadTest {    public static void main(String[]args) {        Thread et=new ExtendsThread();        //此處為體現(xiàn)多線程,同時(shí)開啟兩個(gè)線程        et.start();        //以下即為匿名子類        //直接開啟多線程        new Thread(){            public void run()            {                super.run();                for(int i=0;i<=10;i++)                {                    System.out.println(i+"#"+i);                }            }        }.start();    }}public class ExtendsThread extends Thread {    @Override    public void run() {        super.run();        for(int i=0;i<=10;i++)        {            System.out.println(i+"*"+i);        }    }}

第一次的執(zhí)行結(jié)果

方法二:

1、創(chuàng)建一個(gè)實(shí)現(xiàn)了Runnable接口的類

2、實(shí)現(xiàn)Runnable接口中的抽象方法

3、創(chuàng)建實(shí)現(xiàn)類對(duì)象

4、將此對(duì)象作為參數(shù)傳至Thread類的構(gòu)造器,創(chuàng)造Thread類的對(duì)象

5、利用Thread()類的對(duì)象調(diào)用start()

public class RunnalbeThread implements Runnable//1、創(chuàng)建一個(gè)實(shí)現(xiàn)Runnable的類{    @Override//2、類中重寫Runnable的方法,也就是run方法    public void run() {        for(int i=1;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i);        }    }}public class ThreadTest {    public static void main(String[] args) {        Thread rt=new Thread(new RunnalbeThread());        //3、創(chuàng)建一個(gè)對(duì)應(yīng)類的對(duì)象        //4、將這個(gè)對(duì)象傳入到Thread的構(gòu)造器        rt.start();        //5、用這個(gè)對(duì)應(yīng)的Thread對(duì)象來(lái)繼續(xù)調(diào)用start()        rt.setName("線程3");        for(int i=1;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i+"-"+Thread.currentThread().isAlive());        }    }}

在這個(gè)地方,如果沒(méi)有創(chuàng)建匿名對(duì)象(對(duì)于實(shí)現(xiàn)Runnable的實(shí)現(xiàn)類),一個(gè)實(shí)現(xiàn)類的對(duì)象,可以多次傳入到Thread的構(gòu)造器里面,創(chuàng)造更多的線程

兩種方法的比較

繼承法(方法一)由于Java的單繼承性,導(dǎo)致如果需要繼承Thread類的類由原本的一套體系,可能會(huì)影響該代碼的實(shí)現(xiàn),由此看來(lái),實(shí)現(xiàn)接口的方式是更加活泛的,更自由。

實(shí)操中優(yōu)先選擇Runnable接口的方式

1、實(shí)現(xiàn)的方式?jīng)]有單繼承性的限制

2、實(shí)現(xiàn)的方式更適合多個(gè)線程共享數(shù)據(jù)的情況

注:Thread類也實(shí)現(xiàn)了Runnable接口

Thread類的相關(guān)方法

1、String getName();

返回線程名稱

2、void setName(String name);

設(shè)置線程名稱

public static void main(String[] args) {        Thread et = new ExtendsThread();        et.setName("線程--1");        System.out.printf(et.getName());}

運(yùn)行結(jié)果

此處需要注意的是,主線程也是可以命名的,如以下代碼

public class ThreadTest {    public static void main(String[] args) {        Thread et = new ExtendsThread();        Thread.currentThread().setName("主線程");        System.out.printf(Thread.currentThread().getName());    }}

運(yùn)行結(jié)果如下

3、currentThread()方法

靜態(tài)方法,返回當(dāng)前執(zhí)行此代碼的線程(對(duì)象)

4、yield()方法

釋放當(dāng)前CPU的執(zhí)行權(quán)

也存在當(dāng)我們釋放完執(zhí)行權(quán)之后,CPU再次將執(zhí)行權(quán)分配給目前線程的情況

5、join()方法

相當(dāng)于在原本的線程1上,讓另一個(gè)線程2截?cái)啵肋@個(gè)線程2執(zhí)行結(jié)束,否則不再進(jìn)行線程1(在線程1之中調(diào)用線程2的join方法)

代碼測(cè)試如下

public class ExtendsThread extends Thread{    @Override    public void run() {        super.run();        for(int i=0;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i+"*"+i);        }    }}public class ExtendsThread2 extends Thread{    public void run() {        super.run();        for(int i=0;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i+"#"+i);        }    }}public class ThreadTest {    public static void main(String[] args) {        Thread et = new ExtendsThread();        Thread et2=new ExtendsThread2();        et.start();        et2.start();        et.setName("線程1");        et2.setName("線程2");        Thread.currentThread().setName("主線程");        for(int i=0;i<=20;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i);            if(i%5==0)            {                try {                    et2.join();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

測(cè)試結(jié)果如下

當(dāng)主線程的i跑到5的時(shí)候,此時(shí)調(diào)用了et.join()和et2.join()此時(shí)的主線程已經(jīng)被掛起了,直到線程1和線程2運(yùn)行完之后,才會(huì)繼續(xù)主線程的進(jìn)行。

6、stop()

強(qiáng)制結(jié)束線程,可以提前結(jié)束線程的生命周期。(不推薦使用stop()結(jié)束進(jìn)程)

public class ExtendsThread extends Thread{    @Override    public void run() {        super.run();        for(int i=0;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i+"*"+i);            if(i==5)            {                Thread.currentThread().stop();                //此處用stop強(qiáng)制停止了                //當(dāng)i=5的時(shí)候強(qiáng)制停止線程            }        }    }}public class ThreadTest {    public static void main(String[] args) {        Thread et = new ExtendsThread();        Thread et2=new ExtendsThread2();        et.start();        et.setName("線程1");        Thread.currentThread().setName("主線程");        for(int i=1;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i);        }    }}

測(cè)試結(jié)果

如圖所示,線程1確實(shí)只進(jìn)行到i=5的時(shí)候

7、sleep(long millitime)

強(qiáng)制線程進(jìn)入休眠,單位是毫秒

在指定時(shí)間內(nèi)強(qiáng)制休眠

需要注意的是,對(duì)某個(gè)線程使用sleep的話,該線程就會(huì)進(jìn)入到掛起狀態(tài),在指定時(shí)間掛起。相當(dāng)于主動(dòng)讓出了CPU的執(zhí)行權(quán)。

8、isAlive()

判斷當(dāng)前線程是否存活

舉例如下

public class ExtendsThread extends Thread{    @Override    public void run() {        super.run();        for(int i=0;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i+"-"+Thread.currentThread().isAlive());        }    }}public class ThreadTest {    public static void main(String[] args) {        Thread et = new ExtendsThread();        Thread et2=new ExtendsThread2();        et.start();        et.setName("線程1");        Thread.currentThread().setName("主線程");        for(int i=1;i<=10;i++)        {            System.out.println(Thread.currentThread().getName()+":"+i+"-"+Thread.currentThread().isAlive());        }        System.out.println(et.isAlive());    }}

結(jié)果如下

如圖所示,在代碼的最后,et所開啟的線程已經(jīng)結(jié)束,所以此時(shí)打印出來(lái)的false

線程的調(diào)度

線程的進(jìn)行主要是看時(shí)間片,一般情況下,多個(gè)線程都是并發(fā),所以對(duì)于CPU的執(zhí)行權(quán)一般是進(jìn)行搶奪,高優(yōu)先級(jí)的線程優(yōu)先搶奪CPU的執(zhí)行權(quán)。

說(shuō)到這里就不得不提到線程的優(yōu)先等級(jí)(這里的優(yōu)先級(jí)都是在線程誕生的時(shí)候就是設(shè)置好的,默認(rèn)為5)

>MAX_PRIORITY:10

>MIN_PRIORITY:1

>NORM_PRIORITY:5

也有兩個(gè)方法是關(guān)于線程的優(yōu)先級(jí)

1、getPriority():返回線程優(yōu)先級(jí)

2、setPriority(int newPriority):改變線程的優(yōu)先級(jí)

高優(yōu)先級(jí)搶占低優(yōu)先級(jí)的線程的CPU執(zhí)行權(quán),但是是從概率上而言,高優(yōu)先級(jí)的線程有更大的概率去執(zhí)行CPU

線程的五種狀態(tài)

1、新建:當(dāng)一個(gè)Thread類或其子類的聲明并創(chuàng)建時(shí),新生線程處于此狀態(tài)

2、就緒:當(dāng)線程被start()之后,就會(huì)進(jìn)入隊(duì)列等待CPU的時(shí)間片

3、運(yùn)行:獲得CPU資源,進(jìn)入運(yùn)行狀態(tài),run定義了線程操作和功能

4、阻塞:在某種情況下,被人為掛起或執(zhí)行輸入輸出,讓出CPU的執(zhí)行權(quán)

5、死亡:線程完成了全部工作或被提前強(qiáng)制性中止(stop),或者出現(xiàn)異常導(dǎo)致結(jié)束,比如join()會(huì)使線程被掛起,造成線程阻塞

線程的同步

線程的安全問(wèn)題(不一定出現(xiàn)線程安全問(wèn)題)

沒(méi)有sleep()出現(xiàn)時(shí),錯(cuò)誤的概率小,但是安全問(wèn)題總是要解決的

有可能會(huì)出現(xiàn)極端情況

此時(shí)帶入一個(gè)場(chǎng)景,比如說(shuō)一個(gè)線程代表一個(gè)窗口,一個(gè)售票窗口,線程每進(jìn)行一次就掛起一次,會(huì)打印票號(hào),但是如果正常進(jìn)行,票號(hào)應(yīng)該是連號(hào),但是會(huì)出現(xiàn)如下情況

代碼如下

public class RunnalbeThread implements Runnable{    public static int num=30;    public static int tnum=1;    @Override    public void run() {        while(num!=0)        {            if(num>0)            {                num--;                tnum++;                System.out.println(Thread.currentThread().getName()+":"+tnum);                try {                    Thread.currentThread().sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}public class ThreadTest {    public static void main(String[] args) {        Thread rt3 = new Thread(new RunnalbeThread());        Thread rt2 = new Thread(new RunnalbeThread());        Thread rt = new Thread(new RunnalbeThread());        rt2.start();        rt3.start();        rt.start();        rt3.setName("線程3");        rt.setName("線程1");        rt2.setName("線程2");    }}

代碼測(cè)試結(jié)果如下

很明顯的,會(huì)出現(xiàn)重號(hào)的現(xiàn)象

原因:當(dāng)某個(gè)線程操作票的過(guò)程中,尚未完成操作,另一個(gè)線程參與進(jìn)來(lái),也對(duì)車票進(jìn)行操作(相當(dāng)于是共享數(shù)據(jù))

如何解決

加鎖

當(dāng)一個(gè)線程在操作共享數(shù)據(jù)的時(shí)候,其他線程不能參與,直到線程a操作結(jié)束,其他線程才能開始操作。即使a處于阻塞狀態(tài),也不能被改變

方法一:同步代碼塊

synchronized(同步監(jiān)視器){

需要被同步的代碼}

說(shuō)明:操作共享數(shù)據(jù)的代碼,即為需要被同步的代碼

同步監(jiān)視器,俗稱鎖,可以隨意扔一個(gè)對(duì)象進(jìn)去

要求:多個(gè)線程要共用同一把鎖,不能設(shè)置多個(gè)鎖,此時(shí)不能使用匿名

缺點(diǎn):操作同步代碼時(shí),僅能有一個(gè)線程操作,其他的都在等待,相當(dāng)于是一個(gè)單線程操作過(guò)程,相對(duì)而言效率會(huì)很低

此時(shí)會(huì)出現(xiàn)一個(gè)鎖不唯一的問(wèn)題,由于鎖的創(chuàng)建在Thread的子類中,但是使用此方法創(chuàng)造進(jìn)程需要newThread的子類的對(duì)象,此時(shí)會(huì)new出很多鎖,此時(shí)最好的解決方案就是把鎖進(jìn)行static

方法展示

public class RunnalbeThread implements Runnable{    public static int num=30;    @Override    public void run() {        while(num!=0)        {            try {                Thread.currentThread().sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized (RunnalbeThread.class) {                if(num>0)                {                    num--;                    System.out.println(Thread.currentThread().getName()+":"+num);                }            }        }    }}public class ThreadTest {    public static void main(String[] args) {        Thread rt3 = new Thread(new RunnalbeThread());        Thread rt2 = new Thread(new RunnalbeThread());        Thread rt = new Thread(new RunnalbeThread());        rt2.start();        rt3.start();        rt.start();        rt3.setName("線程3");        rt.setName("線程1");        rt2.setName("線程2");    }}

代碼中,把對(duì)于所有共享數(shù)據(jù)的操作全部都包起來(lái)了,達(dá)到監(jiān)視的作用

結(jié)果如下

還有一個(gè)需要注意的點(diǎn)就是如果是用接口實(shí)現(xiàn)的方法創(chuàng)建的線程,可以考慮使用this的,之所以繼承法不能使用,是因?yàn)槠湟揽縿?chuàng)造他本身的對(duì)象來(lái)創(chuàng)造線程,但是實(shí)現(xiàn)類只創(chuàng)造一個(gè)對(duì)象,其他對(duì)象都是利用Thread進(jìn)行創(chuàng)造的。

但是我的代碼中,監(jiān)視器之后的鎖就不能使用this,因?yàn)樵谥骱瘮?shù)中,我用的創(chuàng)建方法并不是一個(gè)對(duì)象傳入到Thread的構(gòu)造器中,我使用了匿名對(duì)象,如果使用this,每一次的鎖都是不一樣的鎖,無(wú)法起到監(jiān)視作用了

同時(shí),在我的代碼中,使用了synchronized (類名.class)這種方式,在這里需要注意的是,類本身也是一個(gè)對(duì)象,類僅加載一次,與每次new完之后出現(xiàn)的新對(duì)象不同。所以在我看來(lái),類是一個(gè)完美的鎖,不會(huì)出現(xiàn)重復(fù)的現(xiàn)象。

也需要注意對(duì)于同步代碼的包裝。要注意包裝的范圍,少包不能解決安全問(wèn)題,包多了會(huì)影響效率,而且也容易出現(xiàn)新的問(wèn)題。

方式二:

1、同步方法實(shí)現(xiàn)Runnable接口

synchronized可以修飾方法,但是需要符合題意,一般情況下不建議使用

在同步方法的內(nèi)部,就和使用synchronized包起來(lái)是一個(gè)效果

使用同步方法時(shí),同步監(jiān)視器就是this

2、同步方法繼承Thread類的方法

對(duì)于繼承法而言,很明顯不能直接加synchronized,加了synchronized之后,會(huì)自動(dòng)使用this作為監(jiān)視器,很顯然不行,此時(shí)應(yīng)該將方法改成靜態(tài)

總結(jié)同步方法

1、仍涉及同步監(jiān)視器,只是不需要顯式聲明

2、非靜態(tài)的同步方法是this,靜態(tài)方法的監(jiān)視器視為當(dāng)前類本身

衍生內(nèi)容————單例設(shè)計(jì)模式

1、懶漢式(線程安全)

先來(lái)分析一下,在原本對(duì)于懶漢式的代碼中,線程安全可能會(huì)出現(xiàn)的部位

public class Bank {    private Bank(){}    private static Bank instance=null;    public static Bank getInstance()    {        if(instance==null)        {            instance=new Bank();        }        //在此段就容易出現(xiàn)堵塞或者就緒,當(dāng)多線程在此處參與時(shí),設(shè)線程a、線程b        //a判斷了instance==null,已經(jīng)進(jìn)入了語(yǔ)句,此時(shí)CPU將執(zhí)行權(quán)切換給了b或        //a由于某種原因阻塞了,那么此時(shí)可能就不僅僅創(chuàng)建了一個(gè)對(duì)象        return instance;    }}//而在關(guān)于單例式操作,同時(shí)滿足有多個(gè)線程,有共享數(shù)據(jù)這兩個(gè)條件,可以實(shí)現(xiàn)線程安全

本質(zhì)上就是線程a、b搶鎖,誰(shuí)先搶到就誰(shuí)先造

如果想用同步方法,在本例中就可以直接將getInstance這個(gè)方法直接使用synchronized直接修飾,就可以解決線程安全問(wèn)題

如果想使用同步代碼塊,就可以使用synchronized將getInstance這個(gè)方法中的內(nèi)容直接包裹,并且利用Bank.class對(duì)代碼進(jìn)行監(jiān)視(效率差)

同步代碼塊——方法一

public class Bank {    private Bank(){}    private static Bank instance=null;    public static Bank getInstance()    {        if(instance==null)        {            synchronized(Bank.class)            {                instance=new Bank();            }        }        return instance;    }}

同步代碼塊——方法二

public class Bank {    private Bank(){}    private static Bank instance=null;    public static Bank getInstance()    {        synchronized(Bank.class)        {            if(instance==null)            {                instance=new Bank();            }        }        return instance;    }}

兩個(gè)方法在使用上的區(qū)別不大,都可以正常使用,但是實(shí)際上方法一的效率更高

假設(shè)現(xiàn)在有線程1和線程2,當(dāng)線程1率先搶到CPU控制權(quán),先制造了對(duì)象,線程2在方法二中仍停留在synchronized語(yǔ)句上等待,一直到線程1制造完對(duì)象,線程2才能夠進(jìn)入if,判斷失敗之后離開該方法,但是在方法一中,線程2先進(jìn)入判斷,如果1已經(jīng)造完對(duì)象了,那么線程2就會(huì)直接離開。線程2就不會(huì)再進(jìn)入等待區(qū)。

死鎖問(wèn)題

不同的線程分別占用了對(duì)象所需資源不放,都在等對(duì)方放棄,形成死鎖

>不出現(xiàn)異常,不出現(xiàn)提示,所有的線程阻塞,不再進(jìn)行

使用同步的時(shí)候,一定要避免死鎖問(wèn)題出現(xiàn)

鎖的概念

Lock實(shí)際上就是一個(gè)接口,需要有實(shí)現(xiàn)類

Lock接口的具體使用,主要是對(duì)其實(shí)現(xiàn)類:Reentrantlock的使用

Reentrantlock

這個(gè)類有兩個(gè)構(gòu)造器,有一個(gè)形參fair

如果fair是true,就遵循先入先出,按照abc順序開鎖

如果fair是false或者沒(méi)有參數(shù),那么就是abc搶鎖,誰(shuí)先搶到誰(shuí)先開

1、實(shí)例化Reentrantlock

2、將同步代碼放到try中,在try首行調(diào)用Reentrantlock的對(duì)象調(diào)用Lock(),也可以調(diào)用解鎖,try-finally,其中不使用catch,只是想讓finally無(wú)論如果先給Lock解鎖,即使try過(guò)程有異常,也會(huì)給Lock解鎖

(其實(shí)本質(zhì)上也就是上鎖,只不過(guò)Lock需要手動(dòng)開鎖,但是synchronized不需要,synchronized自動(dòng)就會(huì)開鎖)

synchronized和Lock的異同

synchronized機(jī)制在執(zhí)行完同步代碼塊后自動(dòng)釋放同步監(jiān)視器

Lock需要手動(dòng)開鎖,不然會(huì)一直鎖定一個(gè)線程不放

基本都會(huì)使用synchronized,但是實(shí)際上更建議使用Lock

sleep()和wait()的異同

相同:都可以使當(dāng)前線程進(jìn)入阻塞

不同:

1、兩個(gè)方法聲明位置不同,Thread類中聲明sleep(),Object類中聲明wait()

2、調(diào)用范圍不同,sleep()在任何場(chǎng)景都能調(diào)用,wait()必須使用在同步方法或者同步代碼塊中

3、關(guān)于是否釋放同步監(jiān)視器,如果二者都在同步中,sleep()不釋放鎖,但是wait()會(huì)釋放鎖

責(zé)任編輯:

標(biāo)簽:

相關(guān)推薦:

精彩放送:

新聞聚焦
Top