<a href="http://lavasoft.blog.51cto.com/62575/27069/">http://lavasoft.blog.51cto.com/62575/27069/</a>
在java中要想實作多線程,有兩種手段,一種是繼續Thread類,另外一種是實作Runable接口。
對于直接繼承Thread的類來說,代碼大緻架構是:
<a href="http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html">?</a>
<code>class</code> <code>類名</code><code>extends</code> <code>Thread{</code>
<code>方法</code><code>1</code><code>;</code>
<code>方法</code><code>2</code><code>;</code>
<code>…</code>
<code>public</code> <code>void</code> <code>run(){</code>
<code>// other code…</code>
<code>}</code>
<code>屬性</code><code>1</code><code>;</code>
<code>屬性</code><code>2</code><code>;</code>
先看一個簡單的例子:
<code>/**</code>
<code> </code><code>* @author Rollen-Holt 繼承Thread類,直接調用run方法</code>
<code> </code><code>* */</code>
<code>class</code> <code>hello</code><code>extends</code> <code>Thread {</code>
<code> </code><code>public</code> <code>hello() {</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>hello(String name) {</code>
<code> </code><code>this</code><code>.name = name;</code>
<code> </code><code>public</code> <code>void</code> <code>run() {</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i <</code><code>5</code><code>; i++) {</code>
<code> </code><code>System.out.println(name +</code><code>"運作 "</code> <code>+ i);</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code> </code><code>hello h1=</code><code>new</code> <code>hello(</code><code>"A"</code><code>);</code>
<code> </code><code>hello h2=</code><code>new</code> <code>hello(</code><code>"B"</code><code>);</code>
<code> </code><code>h1.run();</code>
<code> </code><code>h2.run();</code>
<code> </code><code>private</code> <code>String name;</code>
【運作結果】:
A運作 0
A運作 1
A運作 2
A運作 3
A運作 4
B運作 0
B運作 1
B運作 2
B運作 3
B運作 4
我們會發現這些都是順序執行的,說明我們的調用方法不對,應該調用的是start()方法。
當我們把上面的主函數修改為如下所示的時候:
<code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code> </code><code>h1.start();</code>
<code> </code><code>h2.start();</code>
然後運作程式,輸出的可能的結果如下:
因為需要用到CPU的資源,是以每次的運作結果基本是都不一樣的,呵呵。
注意:雖然我們在這裡調用的是start()方法,但是實際上調用的還是run()方法的主體。
那麼:為什麼我們不能直接調用run()方法呢?
我的了解是:線程的運作需要本地作業系統的支援。
如果你檢視start的源代碼的時候,會發現:
<code>public</code> <code>synchronized</code> <code>void</code> <code>start() {</code>
<code> </code><code>/**</code>
<code> </code><code>* This method is not invoked for the main method thread or "system"</code>
<code> </code><code>* group threads created/set up by the VM. Any new functionality added</code>
<code> </code><code>* to this method in the future may have to also be added to the VM.</code>
<code> </code><code>*</code>
<code> </code><code>* A zero status value corresponds to state "NEW".</code>
<code> </code><code>*/</code>
<code> </code><code>if</code> <code>(threadStatus !=</code><code>0</code> <code>||</code><code>this</code> <code>!= me)</code>
<code> </code><code>throw</code> <code>new</code> <code>IllegalThreadStateException();</code>
<code> </code><code>group.add(</code><code>this</code><code>);</code>
<code> </code><code>start0();</code>
<code> </code><code>if</code> <code>(stopBeforeStart) {</code>
<code> </code><code>stop0(throwableFromStop);</code>
<code>private</code> <code>native</code> <code>void</code> <code>start0();</code>
注意我用紅色加粗的那一條語句,說明此處調用的是start0()。并且這個這個方法用了native關鍵字,次關鍵字表示調用本地作業系統的函數。因為多線程的實作需要本地作業系統的支援。
但是start方法重複調用的話,會出現java.lang.IllegalThreadStateException異常。
通過實作Runnable接口:
大緻架構是:
<code>class</code> <code>類名</code><code>implements</code> <code>Runnable{</code>
來先看一個小例子吧:
<code> </code><code>* @author Rollen-Holt 實作Runnable接口</code>
<code>class</code> <code>hello</code><code>implements</code> <code>Runnable {</code>
<code> </code><code>hello h1=</code><code>new</code> <code>hello(</code><code>"線程A"</code><code>);</code>
<code> </code><code>Thread demo=</code><code>new</code> <code>Thread(h1);</code>
<code> </code><code>hello h2=</code><code>new</code> <code>hello(</code><code>"線程B"</code><code>);</code>
<code> </code><code>Thread demo1=</code><code>new</code> <code>Thread(h2);</code>
<code> </code><code>demo.start();</code>
<code> </code><code>demo1.start();</code>
【可能的運作結果】:
線程A運作 0
線程B運作 0
線程B運作 1
線程B運作 2
線程B運作 3
線程B運作 4
線程A運作 1
線程A運作 2
線程A運作 3
線程A運作 4
關于選擇繼承Thread還是實作Runnable接口?
其實Thread也是實作Runnable接口的:
<code>class</code> <code>Thread</code><code>implements</code> <code>Runnable {</code>
<code> </code><code>//…</code>
<code>public</code> <code>void</code> <code>run() {</code>
<code> </code><code>if</code> <code>(target !=</code><code>null</code><code>) {</code>
<code> </code><code>target.run();</code>
Thread和Runnable的差別:
如果一個類繼承Thread,則不适合資源共享。但是如果實作了Runable接口的話,則很容易的實作資源共享。
<code> </code><code>* @author Rollen-Holt 繼承Thread類,不能資源共享</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i <</code><code>7</code><code>; i++) {</code>
<code> </code><code>if</code> <code>(count ></code><code>0</code><code>) {</code>
<code> </code><code>System.out.println(</code><code>"count= "</code> <code>+ count--);</code>
<code> </code><code>}</code>
<code> </code><code>hello h1 =</code><code>new</code> <code>hello();</code>
<code> </code><code>hello h2 =</code><code>new</code> <code>hello();</code>
<code> </code><code>hello h3 =</code><code>new</code> <code>hello();</code>
<code> </code><code>h3.start();</code>
<code> </code><code>private</code> <code>int</code> <code>count =</code><code>5</code><code>;</code>
count= 5
count= 4
count= 3
count= 2
count= 1
大家可以想象,如果這個是一個買票系統的話,如果count表示的是車票的數量的話,說明并沒有實作資源的共享。
我們換為Runnable接口:
<code> </code><code>hello he=</code><code>new</code> <code>hello();</code>
<code> </code><code>new</code> <code>Thread(he).start();</code>
總結一下吧:
實作Runnable接口比繼承Thread類所具有的優勢:
1):适合多個相同的程式代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程式的健壯性,代碼可以被多個線程共享,代碼和資料獨立。
是以,本人建議大家勁量實作接口。
<code> </code><code>* @author Rollen-Holt</code>
<code> </code><code>* 取得線程的名稱</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i <</code><code>3</code><code>; i++) {</code>
<code> </code><code>System.out.println(Thread.currentThread().getName());</code>
<code> </code><code>hello he =</code><code>new</code> <code>hello();</code>
<code> </code><code>new</code> <code>Thread(he,</code><code>"A"</code><code>).start();</code>
<code> </code><code>new</code> <code>Thread(he,</code><code>"B"</code><code>).start();</code>
A
B
Thread-0
說明如果我們沒有指定名字的話,系統自動提供名字。
提醒一下大家:main方法其實也是一個線程。在java中是以的線程都是同時啟動的,至于什麼時候,哪個先執行,完全看誰先得到CPU的資源。
在java中,每次程式運作至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用java指令執行一個類的時候,實際上都會啟動一個JVM,每一個jVM實習在就是在作業系統中啟動了一個程序。
判斷線程是否啟動
<code> </code><code>* @author Rollen-Holt 判斷線程是否啟動</code>
<code> </code><code>Thread demo =</code><code>new</code> <code>Thread(he);</code>
<code> </code><code>System.out.println(</code><code>"線程啟動之前---》"</code> <code>+ demo.isAlive());</code>
<code> </code><code>System.out.println(</code><code>"線程啟動之後---》"</code> <code>+ demo.isAlive());</code>
【運作結果】
線程啟動之前---》false
線程啟動之後---》true
主線程也有可能在子線程結束之前結束。并且子線程不受影響,不會因為主線程的結束而結束。
線程的強制執行:
<code> </code><code>* @author Rollen-Holt 線程的強制執行</code>
<code> </code><code>* */</code>
<code> </code><code>class</code> <code>hello</code><code>implements</code> <code>Runnable {</code>
<code> </code><code>public</code> <code>void</code> <code>run() {</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i <</code><code>3</code><code>; i++) {</code>
<code> </code><code>System.out.println(Thread.currentThread().getName());</code>
<code> </code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code> </code><code>hello he =</code><code>new</code> <code>hello();</code>
<code> </code><code>Thread demo =</code><code>new</code> <code>Thread(he,</code><code>"線程"</code><code>);</code>
<code> </code><code>demo.start();</code>
<code> </code><code>for</code><code>(</code><code>int</code> <code>i=</code><code>0</code><code>;i<</code><code>50</code><code>;++i){</code>
<code> </code><code>if</code><code>(i></code><code>10</code><code>){</code>
<code> </code><code>try</code><code>{</code>
<code> </code><code>demo.join(); </code><code>//強制執行demo</code>
<code> </code><code>}</code><code>catch</code> <code>(Exception e) {</code>
<code> </code><code>e.printStackTrace();</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>System.out.println(</code><code>"main 線程執行-->"</code><code>+i);</code>
【運作的結果】:
main 線程執行-->0
main 線程執行-->1
main 線程執行-->2
main 線程執行-->3
main 線程執行-->4
main 線程執行-->5
main 線程執行-->6
main 線程執行-->7
main 線程執行-->8
main 線程執行-->9
main 線程執行-->10
線程
main 線程執行-->11
main 線程執行-->12
main 線程執行-->13
...
線程的休眠:
<code> </code><code>* @author Rollen-Holt 線程的休眠</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>Thread.sleep(</code><code>2000</code><code>);</code>
<code> </code><code>}</code><code>catch</code> <code>(Exception e) {</code>
<code> </code><code>e.printStackTrace();</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() + i);</code>
<code> </code><code>Thread demo =</code><code>new</code> <code>Thread(he,</code><code>"線程"</code><code>);</code>
【運作結果】:(結果每隔2s輸出一個)
線程0
線程1
線程2
線程的中斷:
<code> </code><code>* @author Rollen-Holt 線程的中斷</code>
<code> </code><code>System.out.println(</code><code>"執行run方法"</code><code>);</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>Thread.sleep(</code><code>10000</code><code>);</code>
<code> </code><code>System.out.println(</code><code>"線程完成休眠"</code><code>);</code>
<code> </code><code>}</code><code>catch</code> <code>(Exception e) {</code>
<code> </code><code>System.out.println(</code><code>"休眠被打斷"</code><code>);</code>
<code> </code><code>return</code><code>; </code><code>//傳回到程式的調用處</code>
<code> </code><code>System.out.println(</code><code>"線程正常終止"</code><code>);</code>
<code> </code><code>try</code><code>{</code>
<code> </code><code>Thread.sleep(</code><code>2000</code><code>);</code>
<code> </code><code>e.printStackTrace();</code>
<code> </code><code>demo.interrupt();</code><code>//2s後中斷線程</code>
執行run方法
休眠被打斷
在java程式中,隻要前台有一個線程在運作,整個java程式程序不會小時,是以此時可以設定一個背景線程,這樣即使java程序小時了,此背景線程依然能夠繼續運作。
<code> </code><code>* @author Rollen-Holt 背景線程</code>
<code> </code><code>while</code> <code>(</code><code>true</code><code>) {</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() +</code><code>"在運作"</code><code>);</code>
<code> </code><code>demo.setDaemon(</code><code>true</code><code>);</code>
雖然有一個死循環,但是程式還是可以執行完的。因為在死循環中的線程操作已經設定為背景運作了。
線程的優先級:
<code> </code><code>* @author Rollen-Holt 線程的優先級</code>
<code> </code><code>for</code><code>(</code><code>int</code> <code>i=</code><code>0</code><code>;i<</code><code>5</code><code>;++i){</code>
<code> </code><code>System.out.println(Thread.currentThread().getName()+</code><code>"運作"</code><code>+i);</code>
<code> </code><code>Thread h1=</code><code>new</code> <code>Thread(</code><code>new</code> <code>hello(),</code><code>"A"</code><code>);</code>
<code> </code><code>Thread h2=</code><code>new</code> <code>Thread(</code><code>new</code> <code>hello(),</code><code>"B"</code><code>);</code>
<code> </code><code>Thread h3=</code><code>new</code> <code>Thread(</code><code>new</code> <code>hello(),</code><code>"C"</code><code>);</code>
<code> </code><code>h1.setPriority(</code><code>8</code><code>);</code>
<code> </code><code>h2.setPriority(</code><code>2</code><code>);</code>
<code> </code><code>h3.setPriority(</code><code>6</code><code>);</code>
<code> </code>
A運作0
A運作1
A運作2
A運作3
A運作4
B運作0
C運作0
C運作1
C運作2
C運作3
C運作4
B運作1
B運作2
B運作3
B運作4
。但是請讀者不要誤以為優先級越高就先執行。誰先執行還是取決于誰先去的CPU的資源、
另外,主線程的優先級是5.
線程的禮讓。
線上程操作中,也可以使用yield()方法,将一個線程的操作暫時交給其他線程執行。
<code> </code><code>if</code><code>(i==</code><code>3</code><code>){</code>
<code> </code><code>System.out.println(</code><code>"線程的禮讓"</code><code>);</code>
<code> </code><code>Thread.currentThread().yield();</code>
線程的禮讓
同步和死鎖:
【問題引出】:比如說對于買票系統,有下面的代碼:
<code> </code><code>for</code><code>(</code><code>int</code> <code>i=</code><code>0</code><code>;i<</code><code>10</code><code>;++i){</code>
<code> </code><code>if</code><code>(count></code><code>0</code><code>){</code>
<code> </code><code>try</code><code>{</code>
<code> </code><code>Thread.sleep(</code><code>1000</code><code>);</code>
<code> </code><code>}</code><code>catch</code><code>(InterruptedException e){</code>
<code> </code><code>e.printStackTrace();</code>
<code> </code><code>System.out.println(count--);</code>
<code> </code><code>Thread h1=</code><code>new</code> <code>Thread(he);</code>
<code> </code><code>Thread h2=</code><code>new</code> <code>Thread(he);</code>
<code> </code><code>Thread h3=</code><code>new</code> <code>Thread(he);</code>
<code> </code><code>private</code> <code>int</code> <code>count=</code><code>5</code><code>;</code>
5
4
3
2
1
-1
這裡出現了-1,顯然這個是錯的。,應該票數不能為負值。
如果想解決這種問題,就需要使用同步。所謂同步就是在統一時間段中隻有有一個線程運作,
其他的線程必須等到這個線程結束之後才能繼續執行。
【使用線程同步解決問題】
采用同步的話,可以使用同步代碼塊和同步方法兩種來完成。
【同步代碼塊】:
文法格式:
synchronized(同步對象){
//需要同步的代碼
}
但是一般都把目前對象this作為同步對象。
比如對于上面的買票的問題,如下:
<code> </code><code>synchronized</code> <code>(</code><code>this</code><code>) {</code>
<code> </code><code>if</code><code>(count></code><code>0</code><code>){</code>
<code> </code><code>Thread.sleep(</code><code>1000</code><code>);</code>
<code> </code><code>}</code><code>catch</code><code>(InterruptedException e){</code>
<code> </code><code>System.out.println(count--);</code>
【運作結果】:(每一秒輸出一個結果)
【同步方法】
也可以采用同步方法。
文法格式為synchronized 方法傳回類型 方法名(參數清單){
// 其他代碼
現在,我們采用同步方法解決上面的問題。
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i <</code><code>10</code><code>; ++i) {</code>
<code> </code><code>sale();</code>
<code> </code><code>public</code> <code>synchronized</code> <code>void</code> <code>sale() {</code>
<code> </code><code>if</code> <code>(count ></code><code>0</code><code>) {</code>
<code> </code><code>Thread.sleep(</code><code>1000</code><code>);</code>
<code> </code><code>}</code><code>catch</code> <code>(InterruptedException e) {</code>
<code> </code><code>System.out.println(count--);</code>
<code> </code><code>Thread h1 =</code><code>new</code> <code>Thread(he);</code>
<code> </code><code>Thread h2 =</code><code>new</code> <code>Thread(he);</code>
<code> </code><code>Thread h3 =</code><code>new</code> <code>Thread(he);</code>
【運作結果】(每秒輸出一個)
提醒一下,當多個線程共享一個資源的時候需要進行同步,但是過多的同步可能導緻死鎖。
此處列舉經典的生産者和消費者問題。
【生産者和消費者問題】
先看一段有問題的代碼。
<code>class</code> <code>Info {</code>
<code> </code><code>public</code> <code>String getName() {</code>
<code> </code><code>return</code> <code>name;</code>
<code> </code><code>public</code> <code>void</code> <code>setName(String name) {</code>
<code> </code><code>public</code> <code>int</code> <code>getAge() {</code>
<code> </code><code>return</code> <code>age;</code>
<code> </code><code>public</code> <code>void</code> <code>setAge(</code><code>int</code> <code>age) {</code>
<code> </code><code>this</code><code>.age = age;</code>
<code> </code><code>private</code> <code>String name =</code><code>"Rollen"</code><code>;</code>
<code> </code><code>private</code> <code>int</code> <code>age =</code><code>20</code><code>;</code>
<code> </code><code>* 生産者</code>
<code>class</code> <code>Producer</code><code>implements</code> <code>Runnable{</code>
<code> </code><code>private</code> <code>Info info=</code><code>null</code><code>;</code>
<code> </code><code>Producer(Info info){</code>
<code> </code><code>this</code><code>.info=info;</code>
<code> </code><code>public</code> <code>void</code> <code>run(){</code>
<code> </code><code>boolean</code> <code>flag=</code><code>false</code><code>;</code>
<code> </code><code>for</code><code>(</code><code>int</code> <code>i=</code><code>0</code><code>;i<</code><code>25</code><code>;++i){</code>
<code> </code><code>if</code><code>(flag){</code>
<code> </code><code>this</code><code>.info.setName(</code><code>"Rollen"</code><code>);</code>
<code> </code><code>Thread.sleep(</code><code>100</code><code>);</code>
<code> </code><code>}</code><code>catch</code> <code>(Exception e) {</code>
<code> </code><code>this</code><code>.info.setAge(</code><code>20</code><code>);</code>
<code> </code><code>flag=</code><code>false</code><code>;</code>
<code> </code><code>}</code><code>else</code><code>{</code>
<code> </code><code>this</code><code>.info.setName(</code><code>"chunGe"</code><code>);</code>
<code> </code><code>this</code><code>.info.setAge(</code><code>100</code><code>);</code>
<code> </code><code>flag=</code><code>true</code><code>;</code>
<code> </code><code>* 消費者類</code>
<code>class</code> <code>Consumer</code><code>implements</code> <code>Runnable{</code>
<code> </code><code>public</code> <code>Consumer(Info info){</code>
<code> </code><code>try</code><code>{</code>
<code> </code><code>Thread.sleep(</code><code>100</code><code>);</code>
<code> </code><code>System.out.println(</code><code>this</code><code>.info.getName()+</code><code>"<---->"</code><code>+</code><code>this</code><code>.info.getAge());</code>
<code> </code><code>* 測試類</code>
<code>class</code> <code>hello{</code>
<code> </code><code>Info info=</code><code>new</code> <code>Info();</code>
<code> </code><code>Producer pro=</code><code>new</code> <code>Producer(info);</code>
<code> </code><code>Consumer con=</code><code>new</code> <code>Consumer(info);</code>
<code> </code><code>new</code> <code>Thread(pro).start();</code>
<code> </code><code>new</code> <code>Thread(con).start();</code>
Rollen<---->100
chunGe<---->20
chunGe<---->100
大家可以從結果中看到,名字和年齡并沒有對于。
那麼如何解決呢?
1) 加入同步
2) 加入等待和喚醒
先來看看加入同步會是如何。
<code> </code><code>public</code> <code>synchronized</code> <code>void</code> <code>set(String name,</code><code>int</code> <code>age){</code>
<code> </code><code>this</code><code>.name=name;</code>
<code> </code><code>Thread.sleep(</code><code>100</code><code>);</code>
<code> </code><code>this</code><code>.age=age;</code>
<code> </code><code>public</code> <code>synchronized</code> <code>void</code> <code>get(){</code>
<code> </code><code>System.out.println(</code><code>this</code><code>.getName()+</code><code>"<===>"</code><code>+</code><code>this</code><code>.getAge());</code>
<code>class</code> <code>Producer</code><code>implements</code> <code>Runnable {</code>
<code> </code><code>private</code> <code>Info info =</code><code>null</code><code>;</code>
<code> </code><code>Producer(Info info) {</code>
<code> </code><code>this</code><code>.info = info;</code>
<code> </code><code>boolean</code> <code>flag =</code><code>false</code><code>;</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i <</code><code>25</code><code>; ++i) {</code>
<code> </code><code>if</code> <code>(flag) {</code>
<code> </code>
<code> </code><code>this</code><code>.info.set(</code><code>"Rollen"</code><code>,</code><code>20</code><code>);</code>
<code> </code><code>flag =</code><code>false</code><code>;</code>
<code> </code><code>}</code><code>else</code> <code>{</code>
<code> </code><code>this</code><code>.info.set(</code><code>"ChunGe"</code><code>,</code><code>100</code><code>);</code>
<code> </code><code>flag =</code><code>true</code><code>;</code>
<code>class</code> <code>Consumer</code><code>implements</code> <code>Runnable {</code>
<code> </code><code>public</code> <code>Consumer(Info info) {</code>
<code> </code><code>this</code><code>.info.get();</code>
<code>class</code> <code>hello {</code>
<code> </code><code>Info info =</code><code>new</code> <code>Info();</code>
<code> </code><code>Producer pro =</code><code>new</code> <code>Producer(info);</code>
<code> </code><code>Consumer con =</code><code>new</code> <code>Consumer(info);</code>
Rollen<===>20
ChunGe<===>100
從運作結果來看,錯亂的問題解決了,現在是Rollen 對應20,ChunGe對于100
,但是還是出現了重複讀取的問題,也肯定有重複覆寫的問題。如果想解決這個問題,就需要使用Object類幫忙了、
,我們可以使用其中的等待和喚醒操作。
要完成上面的功能,我們隻需要修改Info類饑渴,在其中加上标志位,并且通過判斷标志位完成等待和喚醒的操作,代碼如下:
<code> </code><code>if</code><code>(!flag){</code>
<code> </code><code>super</code><code>.wait();</code>
<code> </code><code>flag=</code><code>false</code><code>;</code>
<code> </code><code>super</code><code>.notify();</code>
<code> </code><code>if</code><code>(flag){</code>
<code> </code><code>flag=</code><code>true</code><code>;</code>
<code> </code><code>private</code> <code>boolean</code> <code>flag=</code><code>false</code><code>;</code>
<code>【程式運作結果】:</code>
<code>Rollen<===></code><code>20</code>
<code>ChunGe<===></code><code>100</code>
<code>先在看結果就可以知道,之前的問題完全解決。</code>
《完》