从我在Java中使用线程的时间来看,我发现了两种编写线程的方法:
使用可运行的机具:
public class MyRunnable implements Runnable {
public void run() {
//Code
}
}
//Started with a "new Thread(new MyRunnable()).start()" call
或者,使用扩展线程:
public class MyThread extends Thread {
public MyThread() {
super("MyThread");
}
public void run() {
//Code
}
}
//Started with a "new MyThread().start()" call
这两个代码块有什么显著的区别吗?
如果我没有错的话,它或多或少类似于
接口和抽象类之间的区别是什么?
extends建立“Is A”关系,接口提供“Has A”功能。
首选工具可运行:
如果不需要扩展Thread类并修改Thread API默认实现如果你执行的是一个火灾和忘记命令如果您已经在扩展另一个类
首选“扩展线程”:
如果必须重写oracle文档页中列出的任何线程方法
通常,您不需要重写线程行为。因此,在大多数情况下,首选实现Runnable。
另一方面,使用高级ExecutorService或ThreadPoolExecutorServiceAPI提供了更多的灵活性和控制。
看看这个SE问题:
ExecutorService vs休闲线程生成器
对于大多数工作线程来说,最好的方法是将线程完全封装在工作线程类中,这样就不会有任何外部干扰,导致不需要的和无效的线程/类状态。
我刚刚发布了一个示例,因此我也将与您分享:
/**
* This worker can only run once
* @author JayC667
*/
public class ProperThreading {
private final Thread mThread = new Thread(() -> runWorkingLoop()); // if you want worker to be able to run multiple times, move initialisation into startThread()
private volatile boolean mThreadStarted = false;
private volatile boolean mStopRequested = false;
private final long mLoopSleepTime;
public ProperThreading(final long pLoopSleepTime /* pass more arguments here, store in members */ ) {
mLoopSleepTime = pLoopSleepTime;
}
public synchronized void startThread() {
if (mThreadStarted) throw new IllegalStateException("Worker Thread may only be started once and is already running!");
mThreadStarted = true;
mThread.start();
}
private void runWorkingLoop() {
while (!mStopRequested /* && other checks */ ) {
try {
// do the magic work here
Thread.sleep(mLoopSleepTime);
} catch (final InterruptedException e) {
break;
} catch (final Exception e) {
// do at least some basic handling here, you should NEVER ignore exception unless you know exactly what you're doing, and then it should be commented!
}
}
}
public synchronized void stopThread() {
if (!mThreadStarted) throw new IllegalStateException("Worker Thread is not even running yet!");
mStopRequested = true;
mThread.interrupt();
}
}
实际上,将Runnable和Thread相互比较是不明智的。
这两者在多线程中具有相关性和关系,就像机动车的车轮和发动机关系一样。
我想说,多线程只有一种方法,有两个步骤。让我表明我的观点。
可运行:当实现接口Runnable时,这意味着您正在创建可在不同线程中运行的东西。现在创建可以在线程内运行的东西(可以在线程中运行)并不意味着创建线程。因此,MyRunnable类只是一个带有void run方法的普通类。它的对象将是一些普通对象,只有一个在调用时正常执行的方法运行。(除非我们在线程中传递对象)。
线程:class线程,我可以说是一个非常特殊的类,它能够启动一个新的线程,这实际上通过它的start()方法实现了多线程。
为什么不明智地进行比较?因为我们需要这两个线程来实现多线程。
对于多线程,我们需要两件事:
可以在线程内运行的东西(可运行)。可以启动新线程的东西。
因此,从技术上和理论上来说,这两个都是启动线程所必需的,一个线程将运行,另一个线程会使线程运行(就像机动车的车轮和发动机)。
这就是为什么不能使用MyRunnable启动线程,需要将其传递给thread的实例。
但是,只有使用类thread才能创建和运行线程,因为类thread实现了Runnable,所以我们都知道thread内部也是一个Runnable。
最后,Thread和Runnable是多线程的补充,而不是竞争对手或替代者。