看博客要慎重
网上大多数博客的说法是这样的:
通过实现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均失效,因为他们之间不存在数据共享,因为创建他们的对象均不是统一个对象那么为什么会要求不同对象之间数据共享呢?