多線程開發(fā)

多線程是實現(xiàn)并發(fā)機(jī)制的一種有效手段俱笛。進(jìn)程和線程一樣群井,都是實現(xiàn)并發(fā)的一個基本單位赴恨。線程是比進(jìn)程更小的執(zhí)行單位,線程是進(jìn)程的基礎(chǔ)之上進(jìn)行進(jìn)一步的劃分箕憾。所謂多線程是指一個進(jìn)程在執(zhí)行過程中可以產(chǎn)生多個更小的程序單元牡借,這些更小的單元稱為線程,這些線程可以同時存在袭异,同時運行钠龙,一個進(jìn)程可能包含多個同時執(zhí)行的線程。進(jìn)程與線程的區(qū)別如圖所示:


image.png

創(chuàng)建一個線程

在 Java 中實現(xiàn)多線程有兩種手段御铃,一種是繼承 Thread 類碴里,另一種就是實現(xiàn) Runnable 接口。下面我們就分別來介紹這兩種方式的使用畅买。

實現(xiàn) Runnable 接口
class MyThread implements Runnable{ // 實現(xiàn)Runnable接口并闲,作為線程的實現(xiàn)類 
    private String name ;       // 表示線程的名稱 
    public MyThread(String name){ 
        this.name = name ;      // 通過構(gòu)造方法配置name屬性 
    } 
    public void run(){  // 覆寫run()方法,作為線程 的操作主體 
        for(int i=0;i<10;i++){ 
            System.out.println(name + "運行谷羞,i = " + i) ; 
        } 
    } 
}; 
public class RunnableDemo01{ 
    public static void main(String args[]){ 
        MyThread mt1 = new MyThread("線程A ") ;    // 實例化對象 
        MyThread mt2 = new MyThread("線程B ") ;    // 實例化對象 
        Thread t1 = new Thread(mt1) ;       // 實例化Thread類對象 
        Thread t2 = new Thread(mt2) ;       // 實例化Thread類對象 
        t1.start() ;    // 啟動多線程 
        t2.start() ;    // 啟動多線程 
    } 
};
繼承 Thread 類
class MyThread extends Thread{  // 繼承Thread類帝火,作為線程的實現(xiàn)類 
    private String name ;       // 表示線程的名稱 
    public MyThread(String name){ 
        this.name = name ;      // 通過構(gòu)造方法配置name屬性 
    } 
    public void run(){  // 覆寫run()方法溜徙,作為線程 的操作主體 
        for(int i=0;i<10;i++){ 
            System.out.println(name + "運行,i = " + i) ; 
        } 
    } 
}; 
public class ThreadDemo02{ 
    public static void main(String args[]){ 
        MyThread mt1 = new MyThread("線程A ") ;    // 實例化對象 
        MyThread mt2 = new MyThread("線程B ") ;    // 實例化對象 
        mt1.start() ;   // 調(diào)用線程主體 
        mt2.start() ;   // 調(diào)用線程主體 
    } 
};

在線程啟動雖然調(diào)用的是 start() 方法犀填,但實際上調(diào)用的卻是 run() 方法定義的主體蠢壹。

Thread 類和 Runnable 接口

通過 Thread 類和 Runable 兩者有哪些聯(lián)系和區(qū)別呢?
Thread 類的定義九巡。

public class Thread extends Object implements Runnable{......}

從 Thread 類的定義可以清楚的發(fā)現(xiàn)图贸,Thread 類也是 Runnable 接口的子類,但在Thread類中并沒有完全實現(xiàn) Runnable 接口中的 run() 方法冕广,下面是 Thread 類的部分定義疏日。

public Thread(Runnable target,String name){ 
    init(null,target,name,0); 
} 
private void init(ThreadGroup g,Runnable target,String name,long stackSize){ 
    ... 
    this.target=target; 
} 
public void run(){ 
    if(target!=null){ 
        target.run(); 
    } 
}

從定義中可以發(fā)現(xiàn),在 Thread 類中的 run() 方法調(diào)用的是 Runnable 接口中的 run() 方法撒汉,也就是說此方法是由 Runnable 子類完成的沟优,所以如果要通過繼承 Thread 類實現(xiàn)多線程,則必須覆寫 run()睬辐。
實際上 Thread 類和 Runnable 接口之間在使用上也是有區(qū)別的挠阁,如果一個類繼承 Thread類,則不適合于多個線程共享資源溯饵,而實現(xiàn)了 Runnable 接口侵俗,就可以方便的實現(xiàn)資源的共享。

線程的狀態(tài)變化

實現(xiàn)多線程丰刊,必須在主線程中創(chuàng)建新的線程對象隘谣。任何線程一般具有5種狀態(tài),即創(chuàng)建藻三,就緒洪橘,運行,阻塞棵帽,終止。下面分別介紹一下這幾種狀態(tài):

創(chuàng)建狀態(tài)

在程序中用構(gòu)造方法創(chuàng)建了一個線程對象后渣玲,新的線程對象便處于新建狀態(tài)逗概,此時它已經(jīng)有了相應(yīng)的內(nèi)存空間和其他資源,但還處于不可運行狀態(tài)忘衍。新建一個線程對象可采用Thread 類的構(gòu)造方法來實現(xiàn)逾苫,例如 “Thread thread=new Thread()”。

就緒狀態(tài)

新建線程對象后枚钓,調(diào)用該線程的 start() 方法就可以啟動線程铅搓。當(dāng)線程啟動時,線程進(jìn)入就緒狀態(tài)搀捷。此時星掰,線程將進(jìn)入線程隊列排隊多望,等待 CPU 服務(wù),這表明它已經(jīng)具備了運行條件氢烘。

運行狀態(tài)

當(dāng)就緒狀態(tài)被調(diào)用并獲得處理器資源時怀偷,線程就進(jìn)入了運行狀態(tài)。此時播玖,自動調(diào)用該線程對象的 run() 方法椎工。run() 方法定義該線程的操作和功能。

阻塞狀態(tài)

一個正在執(zhí)行的線程在某些特殊情況下蜀踏,如被人為掛起或需要執(zhí)行耗時的輸入/輸出操作维蒙,會讓 CPU 暫時中止自己的執(zhí)行,進(jìn)入阻塞狀態(tài)果覆。在可執(zhí)行狀態(tài)下颅痊,如果調(diào)用sleep(),suspend(),wait() 等方法,線程都將進(jìn)入阻塞狀態(tài)随静,發(fā)生阻塞時線程不能進(jìn)入排隊隊列八千,只有當(dāng)引起阻塞的原因被消除后,線程才可以轉(zhuǎn)入就緒狀態(tài)燎猛。

死亡狀態(tài)

線程調(diào)用 stop() 方法時或 run() 方法執(zhí)行結(jié)束后恋捆,即處于死亡狀態(tài)。處于死亡狀態(tài)的線程不具有繼續(xù)運行的能力重绷。

Java 程序每次運行至少啟動幾個線程沸停?
回答:至少啟動兩個線程,每當(dāng)使用 Java 命令執(zhí)行一個類時昭卓,實際上都會啟動一個 JVM愤钾,每一個JVM實際上就是在操作系統(tǒng)中啟動一個線程,Java 本身具備了垃圾的收集機(jī)制候醒。所以在 Java 運行時至少會啟動兩個線程能颁,一個是 main 線程,另外一個是垃圾收集線程倒淫。

Thread.currentThread().getName(); //取得當(dāng)前線程的名稱
MyThread my=new MyThread(); //定義Runnable子類對象
new Thread(my).start; //系統(tǒng)自動設(shè)置線程名稱
new Thread(my,"線程A").start(); //手工設(shè)置線程名稱

線程操作及方法

線程的強(qiáng)制運行

在線程操作中伙菊,可以使用 join() 方法讓一個線程強(qiáng)制運行,線程強(qiáng)制運行期間敌土,其他線程無法運行镜硕,必須等待此線程完成之后才可以繼續(xù)執(zhí)行。

class MyThread implements Runnable{ // 實現(xiàn)Runnable接口 
    public void run(){  // 覆寫run()方法 
        for(int i=0;i<50;i++){ 
            System.out.println(Thread.currentThread().getName() 
                    + "運行返干,i = " + i) ;  // 取得當(dāng)前線程的名字 
        } 
    } 
}; 
public class ThreadJoinDemo{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 實例化Runnable子類對象 
        Thread t = new Thread(mt,"線程");     // 實例化Thread對象 
        t.start() ; // 啟動線程 
        for(int i=0;i<50;i++){ 
            if(i>10){ 
                try{ 
                    t.join() ;  // 線程強(qiáng)制運行 
                }catch(InterruptedException e){
                } 
            } 
            System.out.println("Main線程運行 --> " + i) ; 
        } 
    } 
};
線程的休眠

在程序中允許一個線程進(jìn)行暫時的休眠兴枯,直接使用 Thread.sleep() 即可實現(xiàn)休眠。

class MyThread implements Runnable{ // 實現(xiàn)Runnable接口 
    public void run(){  // 覆寫run()方法 
        for(int i=0;i<50;i++){ 
            try{ 
                Thread.sleep(500) ; // 線程休眠 
            }catch(InterruptedException e){
            } 
            System.out.println(Thread.currentThread().getName() 
                    + "運行矩欠,i = " + i) ;  // 取得當(dāng)前線程的名字 
        } 
    } 
}; 
public class ThreadSleepDemo{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 實例化Runnable子類對象 
        Thread t = new Thread(mt,"線程");     // 實例化Thread對象 
        t.start() ; // 啟動線程 
    } 
};
中斷線程

當(dāng)一個線程運行時财剖,另外一個線程可以直接通過interrupt()方法中斷其運行狀態(tài)悠夯。

class MyThread implements Runnable{ // 實現(xiàn)Runnable接口 
    public void run(){  // 覆寫run()方法 
        System.out.println("1、進(jìn)入run()方法") ; 
        try{ 
            Thread.sleep(10000) ;   // 線程休眠10秒 
            System.out.println("2峰伙、已經(jīng)完成了休眠") ; 
        }catch(InterruptedException e){ 
            System.out.println("3疗疟、休眠被終止") ; 
            return ; // 返回調(diào)用處 
        } 
        System.out.println("4、run()方法正常結(jié)束") ; 
    } 
}; 
public class ThreadInterruptDemo{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 實例化Runnable子類對象 
        Thread t = new Thread(mt,"線程");     // 實例化Thread對象 
        t.start() ; // 啟動線程 
        try{ 
            Thread.sleep(2000) ;    // 線程休眠2秒 
        }catch(InterruptedException e){ 
            System.out.println("3瞳氓、休眠被終止") ; 
        } 
        t.interrupt() ; // 中斷線程執(zhí)行 
    } 
};
后臺線程

在 Java 程序中策彤,只要前臺有一個線程在運行,則整個 Java 進(jìn)程都不會消失匣摘,所以此時可以設(shè)置一個后臺線程店诗,這樣即使 Java 線程結(jié)束了,此后臺線程依然會繼續(xù)執(zhí)行音榜,要想實現(xiàn)這樣的操作庞瘸,直接使用 setDaemon() 方法即可。

class MyThread implements Runnable{ // 實現(xiàn)Runnable接口 
    public void run(){  // 覆寫run()方法 
        while(true){ 
            System.out.println(Thread.currentThread().getName() + "在運行赠叼。") ; 
        } 
    } 
}; 
public class ThreadDaemonDemo{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 實例化Runnable子類對象 
        Thread t = new Thread(mt,"線程");     // 實例化Thread對象 
        t.setDaemon(true) ; // 此線程在后臺運行 
        t.start() ; // 啟動線程 
    } 
};

在線程類 MyThread 中擦囊,盡管 run() 方法中是死循環(huán)的方式,但是程序依然可以執(zhí)行完嘴办,因為方法中死循環(huán)的線程操作已經(jīng)設(shè)置成后臺運行瞬场。
線程的優(yōu)先級

在 Java 的線程操作中,所有的線程在運行前都會保持在就緒狀態(tài)涧郊,那么此時贯被,哪個線程的優(yōu)先級高,哪個線程就有可能會先被執(zhí)行妆艘。

class MyThread implements Runnable{ // 實現(xiàn)Runnable接口 
    public void run(){  // 覆寫run()方法 
        for(int i=0;i<5;i++){ 
            try{ 
                Thread.sleep(500) ; // 線程休眠 
            }catch(InterruptedException e){
            } 
            System.out.println(Thread.currentThread().getName() 
                    + "運行彤灶,i = " + i) ;  // 取得當(dāng)前線程的名字 
        } 
    } 
}; 
public class ThreadPriorityDemo{ 
    public static void main(String args[]){ 
        Thread t1 = new Thread(new MyThread(),"線程A") ;  // 實例化線程對象 
        Thread t2 = new Thread(new MyThread(),"線程B") ;  // 實例化線程對象 
        Thread t3 = new Thread(new MyThread(),"線程C") ;  // 實例化線程對象 
        t1.setPriority(Thread.MIN_PRIORITY) ;   // 優(yōu)先級最低 
        t2.setPriority(Thread.MAX_PRIORITY) ;   // 優(yōu)先級最高 
        t3.setPriority(Thread.NORM_PRIORITY) ;  // 優(yōu)先級最中等 
        t1.start() ;    // 啟動線程 
        t2.start() ;    // 啟動線程 
        t3.start() ;    // 啟動線程 
    } 
};
優(yōu)先級的大小來決定哪個線程優(yōu)先運行,但是注意并非優(yōu)先級越高就一定會先執(zhí)行批旺,哪個線程先執(zhí)行將由 CPU 的調(diào)度決定幌陕。
線程的禮讓

在線程操作中,也可以使用 yield() 方法將一個線程的操作暫時讓給其他線程執(zhí)行

class MyThread implements Runnable{ // 實現(xiàn)Runnable接口 
    public void run(){  // 覆寫run()方法 
        for(int i=0;i<5;i++){ 
            try{ 
                Thread.sleep(500) ; 
            }catch(Exception e){
            } 
            System.out.println(Thread.currentThread().getName() 
                    + "運行汽煮,i = " + i) ;  // 取得當(dāng)前線程的名字 
            if(i==2){ 
                System.out.print("線程禮讓:") ; 
                Thread.currentThread().yield() ;    // 線程禮讓 
            } 
        } 
    } 
}; 
public class ThreadYieldDemo{ 
    public static void main(String args[]){ 
        MyThread my = new MyThread() ;  // 實例化MyThread對象 
        Thread t1 = new Thread(my,"線程A") ; 
        Thread t2 = new Thread(my,"線程B") ; 
        t1.start() ; 
        t2.start() ; 
    } 
};

線程同步及死鎖

一個多線程的程序如果是通過 Runnable 接口實現(xiàn)的苞轿,則意味著類中的屬性被多個線程共享,那么這樣就會造成一種問題逗物,如果這多個線程要操作同一個資源時就有可能出現(xiàn)資源同步問題。

同步代碼塊
synchronized(同步對象){ 
 需要同步的代碼 
}

class MyThread implements Runnable{ 
    private int ticket = 5 ;    // 假設(shè)一共有5張票 
    public void run(){ 
        for(int i=0;i<100;i++){ 
            synchronized(this){ // 要對當(dāng)前對象進(jìn)行同步 
                if(ticket>0){   // 還有票 
                    try{ 
                        Thread.sleep(300) ; // 加入延遲 
                    }catch(InterruptedException e){ 
                        e.printStackTrace() ; 
                    } 
                    System.out.println("賣票:ticket = " + ticket-- ); 
                } 
            } 
        } 
    } 
}; 
public class SyncDemo02{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 定義線程對象 
        Thread t1 = new Thread(mt) ;    // 定義Thread對象 
        Thread t2 = new Thread(mt) ;    // 定義Thread對象 
        Thread t3 = new Thread(mt) ;    // 定義Thread對象 
        t1.start() ; 
        t2.start() ; 
        t3.start() ; 
    } 
};
同步方法

除了可以將需要的代碼設(shè)置成同步代碼塊外瑟俭,也可以使用 synchronized 關(guān)鍵字將一個方法聲明為同步方法翎卓。

synchronized 方法返回值 方法名稱(參數(shù)列表){ 
}

class MyThread implements Runnable{ 
    private int ticket = 5 ;    // 假設(shè)一共有5張票 
    public void run(){ 
        for(int i=0;i<100;i++){ 
            this.sale() ;   // 調(diào)用同步方法 
        } 
    } 
    public synchronized void sale(){    // 聲明同步方法 
        if(ticket>0){   // 還有票 
            try{ 
                Thread.sleep(300) ; // 加入延遲 
            }catch(InterruptedException e){ 
                e.printStackTrace() ; 
            } 
            System.out.println("賣票:ticket = " + ticket-- ); 
        } 

    } 
}; 
public class SyncDemo03{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 定義線程對象 
        Thread t1 = new Thread(mt) ;    // 定義Thread對象 
        Thread t2 = new Thread(mt) ;    // 定義Thread對象 
        Thread t3 = new Thread(mt) ;    // 定義Thread對象 
        t1.start() ; 
        t2.start() ; 
        t3.start() ; 
    } 
};
死鎖

同步可以保證資源共享操作的正確性,但是過多同步也會產(chǎn)生問題摆寄。例如失暴,現(xiàn)在張三想要李四的畫坯门,李四想要張三的書,張三對李四說“把你的畫給我逗扒,我就給你書”古戴,李四也對張三說“把你的書給我,我就給你畫”兩個人互相等對方先行動矩肩,就這么干等沒有結(jié)果现恼,這實際上就是死鎖的概念。
所謂死鎖黍檩,就是兩個線程都在等待對方先完成叉袍,造成程序的停滯,一般程序的死鎖都是在程序運行時出現(xiàn)的刽酱。

class Zhangsan{ // 定義張三類 
    public void say(){ 
        System.out.println("張三對李四說:“你給我畫喳逛,我就把書給你】美铮”") ; 
    } 
    public void get(){ 
        System.out.println("張三得到畫了润文。") ; 
    } 
}; 
class Lisi{ // 定義李四類 
    public void say(){ 
        System.out.println("李四對張三說:“你給我書,我就把畫給你”") ; 
    } 
    public void get(){ 
        System.out.println("李四得到書了殿怜。") ; 
    } 
}; 
public class ThreadDeadLock implements Runnable{ 
    private static Zhangsan zs = new Zhangsan() ;       // 實例化static型對象 
    private static Lisi ls = new Lisi() ;       // 實例化static型對象 
    private boolean flag = false ;  // 聲明標(biāo)志位典蝌,判斷那個先說話 
    public void run(){  // 覆寫run()方法 
        if(flag){ 
            synchronized(zs){   // 同步張三 
                zs.say() ; 
                try{ 
                    Thread.sleep(500) ; 
                }catch(InterruptedException e){ 
                    e.printStackTrace() ; 
                } 
                synchronized(ls){ 
                    zs.get() ; 
                } 
            } 
        }else{ 
            synchronized(ls){ 
                ls.say() ; 
                try{ 
                    Thread.sleep(500) ; 
                }catch(InterruptedException e){ 
                    e.printStackTrace() ; 
                } 
                synchronized(zs){ 
                    ls.get() ; 
                } 
            } 
        } 
    } 
    public static void main(String args[]){ 
        ThreadDeadLock t1 = new ThreadDeadLock() ;      // 控制張三 
        ThreadDeadLock t2 = new ThreadDeadLock() ;      // 控制李四 
        t1.flag = true ; 
        t2.flag = false ; 
        Thread thA = new Thread(t1) ; 
        Thread thB = new Thread(t2) ; 
        thA.start() ; 
        thB.start() ; 
    } 
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市稳捆,隨后出現(xiàn)的幾起案子赠法,更是在濱河造成了極大的恐慌,老刑警劉巖乔夯,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砖织,死亡現(xiàn)場離奇詭異,居然都是意外死亡末荐,警方通過查閱死者的電腦和手機(jī)侧纯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甲脏,“玉大人眶熬,你說我怎么就攤上這事】榍耄” “怎么了娜氏?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長墩新。 經(jīng)常有香客問我贸弥,道長,這世上最難降的妖魔是什么海渊? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任绵疲,我火速辦了婚禮哲鸳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盔憨。我一直安慰自己徙菠,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布郁岩。 她就那樣靜靜地躺著婿奔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驯用。 梳的紋絲不亂的頭發(fā)上脸秽,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音蝴乔,去河邊找鬼记餐。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播葬毫,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雕沿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起猴仑,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤审轮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辽俗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疾渣,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年崖飘,在試婚紗的時候發(fā)現(xiàn)自己被綠了榴捡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡朱浴,死狀恐怖吊圾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翰蠢,我是刑警寧澤项乒,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站梁沧,受9級特大地震影響板丽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一埃碱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酥泞,春花似錦砚殿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至悯姊,卻和暖如春羡藐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悯许。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工仆嗦, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人先壕。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓瘩扼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親垃僚。 傳聞我的和親對象是個殘疾皇子集绰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

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