我决定面对这个叫做并发的怪物并扩大我的线程知识,所以在我阅读Joshua Bloch的书之前,我决定随机编写一些代码来帮助我理解在阅读本书之前我可能面临的问题,希望我能够然后来到我的代码并进行更正,但随后我进入了这个坑,我希望有人可以解释。
我有以下内容:
public class Arithmetic implements Runnable {
int number;
public Arithmetic(int x){
this.number = number + x;
}
@Override
public void run() {
Thread.currentThread().setName("thread-"+number +" > " + "number = "+getNumber());
System.out.println(Thread.currentThread().getName());
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = getNumber() + number;
}
}
然后是一个主要的课程:
public class Main {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
for (int x=0; x<=5; x++){
Thread thread = new Thread(new Arithmetic(x));
thread.start();
}
}
}
有了这个,我得到以下输出:
run:
main
thread-0 > number = 0
thread-1 > number = 1
thread-2 > number = 2
thread-3 > number = 3
thread-5 > number = 5
thread-4 > number = 4
注意:5在4之前
但后来我把我的主班改为:
public class Main {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
for (int x=0; x<=5; x++){
Runnable runnable = new Arithmetic(x);
runnable.run();
}
}
}
我得到以下输出:
run:
main
thread-0 > number = 0
thread-1 > number = 1
thread-2 > number = 2
thread-3 > number = 3
thread-4 > number = 4
thread-5 > number = 5
注意:正确的序列
我希望两个main(s)都会产生不稳定的结果(比如Thread实现),然后我会使用一些线程安全措施,比如同步访问等,但为什么Runnable调用就好像Arithmetic
一样线程安全?
IMO,扩展Thread类和实现Runnable之间的区别在于解耦目的。抱歉,如果这是一个重复的问题,我似乎无法找到答案。
提前致谢。
答案 0 :(得分:3)
Runnables
不要简单地启动新线程和接口,这意味着你的第二段代码同步运行。
Threads
是新线程,因此它们可以并行运行,这就是输出无序的原因 - 第4个线程的执行速度比第5个慢。
答案 1 :(得分:2)
事情就是当你做的时候
Thread t = new Thread(new Arithemetic())
t.start();
线程t
已启动并执行Arithmetic
。
在您的情况下,您正在调用runnable.run();
,这意味着当前线程将调用run()
内的代码。它类似于调用任何其他方法。
最终,您当前的线程本身正在执行run
方法5次
答案 2 :(得分:1)
您的Runnables都在主线程中执行(并且在该代码中只有一个“主”线程)。
您的线程都是单独执行的,并且java不保证一旦启动线程将以任何特定顺序执行。
答案 3 :(得分:0)
因为Runnable
本身不在单独的线程上运行。它只是一个用于传递方法实现的接口。这样的一个例子就是将它传递给Thread
构造函数(就像你在第一个例子中所做的那样)。因此,在您的第二个示例中,没有任何内容同时执行;它只是一个接一个地执行run()
方法。