【Java并發(fā)編程】2.1對象及變量的并發(fā)訪問——synchronized同步方法

前言

著重掌握如下技術(shù)點(diǎn):
1.synchronized 對象監(jiān)視器為Object的使用暂幼;
2.synchronized 對象監(jiān)視器為Class時的使用蛛碌;
3.非線程安全時如何出現(xiàn)的炕檩;
4.關(guān)機(jī)字volatile的主要作用屎飘;
5.關(guān)鍵字volatile與synchronized的區(qū)別與使用情況凡人。

synchronized同步方法

非線程安全會在多個線程對同一個對象中的實(shí)例變量進(jìn)行并發(fā)訪問時發(fā)生措伐,產(chǎn)生的后果就是“臟讀”唠亚,也就是取到的數(shù)據(jù)是被更改過的区丑。
而線程安全就是已獲得的實(shí)例變量的值是經(jīng)過同步處理的棘利,不會出現(xiàn)臟讀的線程橱野。

2.1.1方法內(nèi)的變量為線程安全

“非線程安全”問題存在于“實(shí)例變量中”朽缴,如果是方法內(nèi)部的私有變量善玫,則不存在“非線程安全問題”,所以結(jié)果也是線程安全的密强。
下面例子實(shí)現(xiàn)方法內(nèi)部聲明一個變量茅郎,是不存在非線程安全問題的。

public class HasSelfPrivateNum {

    public void addI(String userName) {
        int num;
        if(userName.equals("a")){
            num=100;
            System.out.println("a set off");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            num=200;
            System.out.println("b set off");
        }
        System.out.println(userName+" num="+num);
    }
}

class ThreadA extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadA(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("a");
    }
}

class ThreadB extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadB(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }
}

class Run{
    public static void main(String[] args) {
        HasSelfPrivateNum numRef = new HasSelfPrivateNum();
        ThreadA threadA = new ThreadA(numRef);
        threadA.start();
        ThreadB threadB = new ThreadB(numRef);
        threadB.start();
    }
}

結(jié)果為:

b set off
b num=200
a set off
a num=100

可見方法中的內(nèi)部變量num所執(zhí)行的操作 不存在非線程安全問題或渤。

2.1.2實(shí)例變量非線程安全

如果多個線程共同訪問一個對象中的實(shí)例變量就有可能出現(xiàn)“非線程安全問題”系冗。
用線程訪問的對象中如果有多個實(shí)例變量,則運(yùn)行結(jié)果有可能出現(xiàn)交叉的情況薪鹦。
如果對象中僅有一個實(shí)例變量掌敬,則有可能出現(xiàn)覆蓋。

/**
 * 實(shí)例變量num被多個線程訪問
 * @author Arthur
 * @date 2017-12-25 14:15
 */

public class HasSelfPrivateNum {

    private int num =0;

    public void addI(String userName) {
        if(userName.equals("a")){
            num=100;
            System.out.println("a set off");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            num=200;
            System.out.println("b set off");
        }
        System.out.println(userName+" num="+num);
    }
}

class ThreadA extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadA(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("a");
    }
}

class ThreadB extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadB(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }
}

class Run{
    public static void main(String[] args) {
        HasSelfPrivateNum numRef = new HasSelfPrivateNum();
        ThreadA threadA = new ThreadA(numRef);
        threadA.start();
        ThreadB threadB = new ThreadB(numRef);
        threadB.start();
    }
}
a set off
b set off
b num=200
a num=200

本例子是兩個線程同時訪問一個沒用同步的的方法池磁,如果兩個線程同時操作業(yè)務(wù)對象中的實(shí)例變量奔害,則會出現(xiàn)“非線程安全”問題。解決方案是只要在方法前加synchronized關(guān)鍵字即可地熄。在兩個線程訪問同一個對象中的同步方法時一定是線程安全的华临。

2.1.3多個對象多個鎖

public class HasSelfPrivateNum {

    private int num = 0;

    synchronized  public void addI(String userName) {
        if(userName.equals("a")){
            num=100;
            System.out.println("a set off");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            num=200;
            System.out.println("b set off");
        }
        System.out.println(userName+" num="+num);
    }
}

class ThreadA extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadA(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("a");
    }
}

class ThreadB extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadB(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }
}

class Run{
    public static void main(String[] args) {
        HasSelfPrivateNum numRef = new HasSelfPrivateNum();
        HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
        ThreadA threadA = new ThreadA(numRef);
        threadA.start();
        ThreadB threadB = new ThreadB(numRef2);
        threadB.start();
    }
}
a set off
b set off
b num=200
a num=100

上述代碼由于創(chuàng)建了2個HasSelfPrivateNum 實(shí)例,擁有了兩個鎖端考,雖然方法是同步的雅潭,但是造成的結(jié)果卻是異步的。效果是先打印出b的值 再打印出a的值却特。
為什么是這樣的呢扶供?synchronized關(guān)鍵字是對對象加鎖,而不是對方法或代碼塊加鎖裂明,上述例子中哪個線程先執(zhí)行帶synchronized的方法椿浓,哪個線程就先獲得該方法所屬對象的鎖Lock,其他線程等待,前提是多個線程訪問的是同一個對象轰绵。
但如果多個線程訪問多個對象粉寞,JVM就會創(chuàng)建多個鎖。上述問題就是如此左腔。

2.1.4synchronized方法與鎖對象

為了驗(yàn)證線程鎖的是對象唧垦,代碼如下:

/**
 * 驗(yàn)證線程鎖的是對象
 *
 * @author Arthur
 * @date 2017-12-26 16:08
 */

public class SynchronizedMethodLock {
    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        MyThreadA myThreadA = new MyThreadA(myObject);
        MyThreadB myThreadB = new MyThreadB(myObject);
        myThreadA.setName("A");
        myThreadB.setName("B");
        myThreadA.start();
        myThreadB.start();
    }
}

class MyObject{
    public void method() throws InterruptedException {
        System.out.println("begin threadName:"+Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println("end");
    }
}
class MyThreadA extends Thread{

    private MyObject myObject;

    public MyThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        super.run();
        try {
            myObject.method();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MyThreadB extends Thread{

    private MyObject myObject;

    public MyThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        super.run();
        try {
            myObject.method();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

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

begin threadName:A
begin threadName:B
A end
B end

當(dāng)method()方法用synchronized修飾時

public synchronized void method() 

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

begin threadName:A
A end
begin threadName:B
B end

可見調(diào)用關(guān)鍵字synchronized聲明的方法一定是排隊(duì)運(yùn)行的。另外只有共享的資源的讀寫訪問才需要同步化處理液样!
那其他方法在被調(diào)用時是什么效果呢振亮?如何查看Lock鎖對象的效果呢?更新代碼如下:

/**
 * 驗(yàn)證線程鎖的是對象
 *
 * @author Arthur
 * @date 2017-12-26 16:08
 */

public class SynchronizedMethodLock {
    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        MyThreadA myThreadA = new MyThreadA(myObject);
        MyThreadB myThreadB = new MyThreadB(myObject);
        myThreadA.setName("A");
        myThreadB.setName("B");
        myThreadA.start();
        myThreadB.start();
    }
}

class MyObject{
    public /*synchronized*/ void method() throws InterruptedException {
        System.out.println("begin threadName:"+Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(Thread.currentThread().getName()+" end");
    }
}
class MyThreadA extends Thread{

    private MyObject myObject;

    public MyThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        super.run();
        try {
            myObject.method();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MyThreadB extends Thread{

    private MyObject myObject;

    public MyThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        super.run();
        try {
            myObject.method();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

結(jié)果如下

begin threadName:A
begin threadName:B
A end
B end

可以看到即使methodA為同步方法鞭莽,線程A持有了myObject對象的鎖坊秸,但是線程B仍能夠異步調(diào)用非synchronized方法methodB。
繼續(xù)試驗(yàn)澎怒,在methodB方法上也加上synchronized

public synchronized void methodB() 

運(yùn)行結(jié)果為按順序執(zhí)行褒搔。

begin methodA threadName:A
A end
begin methodB threadName:B
B end

以此可以得出結(jié)論
1)A線程先持有object對象的鎖,B線程可以以異步的方法調(diào)用object對象中非synchronized的方法喷面。
2)A線程先持有object對象的鎖星瘾,B線程如果這時調(diào)用object對象中的synchronized的方法那么需要等待,也就是同步惧辈。

2.1.5臟讀

前面說明了在多個線程調(diào)用同一方法時琳状,為了避免數(shù)據(jù)交叉的情況,用synchroinized同步盒齿。但是有些操作雖然在賦值時進(jìn)行了同步念逞,但在取值的時候可能出現(xiàn)意外,這種情況就是臟讀边翁。發(fā)生臟讀的情況是在讀取實(shí)例變量的時候翎承,此值已經(jīng)被其他線程更改過了。

/**
 * 臟讀現(xiàn)象
 *
 * @author Arthur
 * @date 2017-12-26 17:07
 */

public class Run {
    public static void main(String[] args) throws InterruptedException {
        PublicVar varRef = new PublicVar();
        ThreadA threadA = new ThreadA(varRef);
        threadA.start();
        threadA.setName("threadA");
        Thread.sleep(200);//打印結(jié)果受此值大小影響
        varRef.getValue();
    }
}
class PublicVar{
    public String username = "A";
    public String password = "AA";

    synchronized public void setValue(String username, String password) {
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setValue method threadName="+Thread.currentThread().getName()+" username="+username+" password="+password);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void getValue() {
        System.out.println("getValue method threadName="+Thread.currentThread().getName()+" username="+username+" password="+password);
    }
}

class ThreadA extends Thread{
    private PublicVar var;

    public ThreadA(PublicVar var) {
        this.var = var;
    }

    @Override
    public void run() {
        super.run();
        var.setValue("B","BB");
    }
}

程序運(yùn)行為:

getValue method threadName=main username=B password=AA
setValue method threadName=threadA username=B password=BB

出現(xiàn)臟讀是因?yàn)閜ublic void getValue()方法不是同步的倒彰,所以在任意時刻都可以調(diào)用审洞。
解決方案是加上同步關(guān)鍵字

synchronized public void getValue() {
        System.out.println("getValue method threadName="+Thread.currentThread().getName()+" username="+username+" password="+password);
    }

程序運(yùn)行正常,setValue和getValue被依次執(zhí)行。

setValue method threadName=threadA username=B password=BB
getValue method threadName=main username=B password=BB

小結(jié):
1.當(dāng)A線程調(diào)用anyObject的synchronized的X方法時待讳,就取得了X方法鎖芒澜,更準(zhǔn)確的來說是anyObject的對象鎖,所以其他線程必須等A線程執(zhí)行完X方法才能調(diào)用X方法创淡,但是其他線程可以所以調(diào)用非synchronized的方法痴晦。
2.當(dāng)A線程調(diào)用anyObject的synchronized的X方法時,就取得了X方法鎖琳彩,更準(zhǔn)確的來說是anyObject的對象鎖誊酌,所以其他線程必須等A線程執(zhí)行完X方法才能調(diào)用X方法部凑,但是如果其他線程B調(diào)用聲明了synchronized的非X方法時,由于對象鎖被A線程持有碧浊,必須等A線程執(zhí)行完X方法后涂邀,才能執(zhí)行synchronized的非X方法。這種情況不會出現(xiàn)臟讀現(xiàn)象箱锐。

2.1.6鎖重入

synchronized擁有鎖重入功能比勉,通俗的講當(dāng)某個線程獲得對象鎖以后,在此請求此對象鎖可以在此得到該對象的鎖驹止。這也證明在一個synchronized方法/塊內(nèi)部調(diào)用本類的其他synchronized方法/塊是永遠(yuǎn)可以得到鎖的浩聋。
看代碼:

/**
 * 鎖重入
 * @author Arthur
 * @date 2017-12-26 17:25
 */

public class Run {
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        threadA.start();
    }
}

class Service{

    public synchronized void service1() {
        System.out.println("service1.");
        service2();
    }

    public synchronized void service2(){
        System.out.println("service2.");
        service3();
    }

    public synchronized void service3(){
        System.out.println("service3.");
    }

}

class ThreadA extends Thread{

    @Override
    public void run() {
        super.run();
        Service service = new Service();
        service.service1();
    }
}

結(jié)果為

service1.
service2.
service3.

可重入的概念:當(dāng)一個線程持有對象鎖時,此時這個對象鎖還未被釋放臊恋,當(dāng)它再次請求獲得鎖時還是可以獲得衣洁。如果不能重入就會造成死鎖。
重入鎖也支持在父子類中調(diào)用抖仅。

2.1.7出現(xiàn)異常坊夫,鎖自動釋放

當(dāng)一個線程執(zhí)行異常時,其所持有的鎖自動釋放岸售。

2.1.8同步不具有繼承性

/**
 * 同步不具有繼承性
 *
 * @author Arthur
 * @date 2017-12-26 17:37
 */

public class Run {
    public static void main(String[] args) {
        Sub subRef = new Sub();
        ThreadA threadA = new ThreadA(subRef);
        threadA.setName("A");
        threadA.start();
        ThreadB threadB = new ThreadB(subRef);
        threadB.setName("B");
        threadB.start();
    }
}

class Main{
    synchronized public void sleep(){
        try {
            System.out.println(" Main 下一步 sleep begin thread name="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println(" Main 下一步 sleep end thread name="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Sub extends Main{
    @Override
    public void sleep(){
        super.sleep();
        try {
            System.out.println(" Sub 下一步 sleep begin thread name="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println(" Sub 下一步 sleep end thread name="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadA extends Thread{

    private Sub sub;

    public ThreadA(Sub sub) {
        this.sub = sub;
    }

    @Override
    public void run() {
        super.run();
        sub.sleep();
    }
}

class ThreadB extends Thread{

    private Sub sub;

    public ThreadB(Sub sub) {
        this.sub = sub;
    }

    @Override
    public void run() {
        super.run();
        sub.sleep();
    }
}

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

 Main 下一步 sleep begin thread name=A time=1514281689722
 Main 下一步 sleep end thread name=A time=1514281694722
 Main 下一步 sleep begin thread name=B time=1514281694722 
 Sub 下一步 sleep begin thread name=A time=1514281694722
 Main 下一步 sleep end thread name=B time=1514281699723
 Sub 下一步 sleep begin thread name=B time=1514281699723
 Sub 下一步 sleep end thread name=A time=1514281699723
 Sub 下一步 sleep end thread name=B time=1514281704723

由結(jié)果可看出同步未被繼承践樱。在子類的方法加上synchronized

public synchronized void sleep()

程序運(yùn)行正常:

 Main 下一步 sleep begin thread name=B time=1514281920201
 Main 下一步 sleep end thread name=B time=1514281925201
 Sub 下一步 sleep begin thread name=B time=1514281925201
 Sub 下一步 sleep end thread name=B time=1514281930201
 Main 下一步 sleep begin thread name=A time=1514281930201
 Main 下一步 sleep end thread name=A time=1514281935202
 Sub 下一步 sleep begin thread name=A time=1514281935202
 Sub 下一步 sleep end thread name=A time=1514281940202

下一節(jié)介紹2.2 synchronized同步語句塊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厂画,一起剝皮案震驚了整個濱河市凸丸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌袱院,老刑警劉巖屎慢,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異忽洛,居然都是意外死亡腻惠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門欲虚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來集灌,“玉大人,你說我怎么就攤上這事复哆⌒佬” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵梯找,是天一觀的道長唆阿。 經(jīng)常有香客問我,道長锈锤,這世上最難降的妖魔是什么驯鳖? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任闲询,我火速辦了婚禮,結(jié)果婚禮上浅辙,老公的妹妹穿的比我還像新娘扭弧。我一直安慰自己,他們只是感情好记舆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布寄狼。 她就那樣靜靜地躺著,像睡著了一般氨淌。 火紅的嫁衣襯著肌膚如雪泊愧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天盛正,我揣著相機(jī)與錄音删咱,去河邊找鬼。 笑死豪筝,一個胖子當(dāng)著我的面吹牛痰滋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播续崖,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼敲街,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了严望?” 一聲冷哼從身側(cè)響起多艇,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎像吻,沒想到半個月后峻黍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拨匆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年姆涩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惭每。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡骨饿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出台腥,到底是詐尸還是另有隱情宏赘,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布览爵,位于F島的核電站置鼻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蜓竹。R本人自食惡果不足惜箕母,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一储藐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嘶是,春花似錦钙勃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至希太,卻和暖如春克饶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背誊辉。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工矾湃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人堕澄。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓邀跃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蛙紫。 傳聞我的和親對象是個殘疾皇子拍屑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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

  • Java8張圖 11、字符串不變性 12坑傅、equals()方法僵驰、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,693評論 0 11
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法裁蚁,類相關(guān)的語法矢渊,內(nèi)部類的語法,繼承相關(guān)的語法枉证,異常的語法,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • 從三月份找實(shí)習(xí)到現(xiàn)在移必,面了一些公司室谚,掛了不少,但最終還是拿到小米崔泵、百度秒赤、阿里、京東憎瘸、新浪入篮、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,192評論 11 349
  • 一:java概述:1幌甘,JDK:Java Development Kit潮售,java的開發(fā)和運(yùn)行環(huán)境痊项,java的開發(fā)工...
    ZaneInTheSun閱讀 2,629評論 0 11
  • 我的大學(xué)生活應(yīng)該這么過,當(dāng)我工作的時候不會感到因?yàn)樵?jīng)荒廢學(xué)業(yè)而后悔酥诽,年老時不會因?yàn)槔速M(fèi)青春而嘆息鞍泉,我要把釋放,天...
    TK12閱讀 303評論 0 1