看博客要慎重
網上大多數博客的說法是這樣的:
通過實現Thread類的線程之間數據不共享,而實現Runnable接口的線程之間數據共享。
我一直在想,這沒有道理啊,Thread也是實現Runnable的,而Runnable裏只有一個run方法,歸根結底線程的操作均是操作Thread,那爲什麼會有區別呢?
直到某一天,我突然回過神,看了看所謂數據不共享的代碼,突然明白了,廢話少說上代碼。
以下是衆多博客下關於Thread和Runnable數據共享的例子:
實現Runnable
代碼塊一
public class Main {
public static void main(String[] args) {
demo2 demo = new demo2();
Thread thread1 = new Thread(demo);
Thread thread2 = new Thread(demo);
Thread thread3 = new Thread(demo);
Thread thread4 = new Thread(demo);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
class demo2 implements Runnable{
int i=0;
@Override
public void run(){
System.out.println(i);
i++;
}
}
其結果是
繼承Thread:
代碼塊二
public class Main {
public static void main(String[] args) {
demo1 demo1 = new demo1();
demo1 demo2 = new demo1();
demo1 demo3 = new demo1();
demo1 demo4 = new demo1();
demo1.start();
demo2.start();
demo3.start();
demo4.start();
}
}
class demo1 extends Thread{
int i=0;
@Override
public void run(){
System.out.println(i);
i++;
}
}
其結果是:
看到這裏是不是覺得繼承Thread類的線程真的數據不共享?
那就大錯特錯了,看看上面繼承Thread類的例子,它是怎麼建立線程的?都是重複實例demo1,然後start,請問?一個類不同對象之間怎麼共享變量?( 此處忽略靜態變量 )
我笑了,如果按照這種寫法,Runnable也可以數據不共享,如下:
代碼塊三
public class Main {
public static void main(String[] args) {
demo2 demo1 = new demo2();
demo2 demo2 = new demo2();
demo2 demo3 = new demo2();
demo2 demo4 = new demo2();
Thread thread1 = new Thread(demo1);
Thread thread2 = new Thread(demo2);
Thread thread3 = new Thread(demo3);
Thread thread4 = new Thread(demo4);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
class demo2 implements Runnable{
int i=0;
@Override
public void run(){
System.out.println(i);
i++;
}
}
這段代碼的結果爲,
所以這就是一個錯誤,網上各種博客無腦抄的錯誤,所以正確方法是:
代碼塊四
public class Main {
public static void main(String[] args) {
demo1 demo = new demo1();
Thread thread1 = new Thread(demo);
Thread thread2 = new Thread(demo);
Thread thread3 = new Thread(demo);
Thread thread4 = new Thread(demo);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
class demo1 extends Thread{
int i=0;
@Override
public void run(){
System.out.println(i);
i++;
}
}
對同一對象創建線程,各個線程之間所有數據均共享。
有的人會說爲什麼要new Thread,這不是多此一舉嗎?是,如果沒有變量共享要求,這樣的確是多此一舉,但是如果需要共享變量就必須這麼寫,而且
如果按照代碼塊二的寫法,synchronize和volatile均失效,因爲他們之間不存在數據共享,因爲創建他們的對象均不是統一個對象那麼爲什麼會要求不同對象之間數據共享呢?