package com.wc82; public class ThreadClassVarTest { public static void main(String[] args) { HelloThread r = new HelloThread(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class HelloThread implements Runnable { private int i=0; @Override public void run() { for(;i<50;) { synchronized (this) { System.out.println("Hello number: " + i++); } try { Thread.sleep(20); //Thread.sleep((long) Math.random() * 1000); 這樣的寫法是錯誤的,因為括號的優先級, //相當於Thread.sleep(0),這時線程不再進行阻塞,各個線程之間會搶占cpu,接口會出錯,會打印出50 } catch (InterruptedException e) { e.printStackTrace(); } } } }
該例子中,HelloThread類實現了Runnable接口,其中run()方法的主要工作是輸出"Hello number: "字符串加數字i,並且同時遞增i,當i到達50時,退出循環。
main()方法中生成了一個HelloThread類的對象r,並且利用這個一個對象生成了兩個線程。
程序的執行結果是:順次打印了0到49的數字,共50個數字。
這是因為,i是成員變量,則HelloThread的對象r只包含這一個i,兩個Thread對象因為由r構造,所以共享了同一個i。
當我們改變代碼時(原先的成員變量i被注釋掉,增加了方法中的局部變量i):
將以下代碼修改
for(;i<50;)
改為
for(int i=0;i<50;)
如注釋中所述,由於局部變量對於每一個線程來說都有自己的拷貝,所以各個線程之間不再共享同一個變量,輸出結果為100個數字,實際上是兩組,每組都是0到49的50個數字,並且兩組數字之間隨意地穿插在一起。
得到的結論如下:
如果一個變量是成員變量,那么多個線程對同一個對象的成員變量進行操作時,它們對該成員變量是彼此影響的,也就是說一個線程對成員變量的改變會影響到另一個線程。
如果一個變量是局部變量,那么每個線程都會有一個該局部變量的拷貝(即便是同一個對象中的方法的局部變量,也會對每一個線程有一個拷貝),一個線程對該局部變量的改變不會影響到其他線程。