在java中可有两种方式实现多线程:
1. 继承Thread类
2. 是实现Runnable接口
由于Java不支持多继承,所以推荐使用实现Runnable接口的方法。
如果想要新建一个线程类,那么只需要override run() method就好了。
实现Runnable的类在创建新线程的时候用 Tread tread = new Tread(实现Runnable接口的类),就完成了Tread的创建。
- State transitions of a thread
Thread类的两个主要method: start() 和 run()的区别
start()
- 让thread进入 runnable 状态
- call run() method
- extend Thread Class不用override start() method
run()
- 当thread运行时被调用
- run()在thread创建完了之后被调用
- Runnable类里的run()没有任何内容,所以一定要实现
在Java中,GUI的绘制和事件的处理都是集中在一个线程之中完成的,这个线程叫做Event Dispatcher Thread - 事件分发线程 简称EDT
我在CSDN上发现了一个关于Swing EDT的很好的文章 【Java线程】Swing事件分发线程EDT与SwingUtilities.invokeLater
"EDT:Swing程序只有一个EDT,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。"
简单来说EDT机制是为了防止GUI的绘制和事件互相影响(interrupted)。
为什么要在这里谈到EDT呢?
因为下面一个概念不是很好理解(至少javadoc写得很模糊): Platform.runLater(): 如果你有多个线程,其中包括一个GUI线程(也就是EDT),一个是没有GUI的线程。比如说你需要完成一个进度条,但是如何才能让进度(非GUI线程)和进度条(GUI线程)相互关联呢?那么Platform.runlater()就很有用了。
Platform.runlater()的具体实现也有主要两种方法,比如说我们想要创建一个从1数到1,000,000的进度条:
第一种写法是这样的:
Code using PlatForm.RunLater :
final ProgressBar bar = new ProgressBar(); new Thread(new Runnable() { @Override public void run() { for (int i=1; i<=1000000; i++) { final int counter = i; Platform.runLater(new Runnable() { @Override public void run() { bar.setProgress(counter/1000000.0); } }); } } }).start();
第一种写法其实是一种很反人类的写法,你的脑子会因为两个Runnable多死几个细胞!
第二种实现是:
Code using Task :
Task task = new Task<Void>() { @Override public Void run() { static final int max = 1000000; for (int i=1; i<=max; i++) { updateProgress(i, max); } return null; } }; ProgressBar bar = new ProgressBar(); bar.progressProperty().bind(task.progressProperty()); new Thread(task).start();
这样的写法就简洁很多。
具体的讨论详见stackoverflow: Platform.Runlater and Task Javafx
但不是说我们不能用Platform.runlater(),下面是一个使用Platform.runlater()实现进度条的例子。
import java.util.concurrent.locks.ReentrantLock; import javafx.application.Application; import static javafx.application.Application.launch; import javafx.application.Platform; import javafx.concurrent.Task; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; import javafx.scene.control.ProgressIndicator; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage; public class BetterProgressTest extends Application { ProgressBar bar; ProgressIndicator indicator; Button button; Label processLabel; int numTasks = 0; ReentrantLock progressLock; @Override public void start(Stage primaryStage) throws Exception { progressLock = new ReentrantLock(); VBox box = new VBox(); HBox toolbar = new HBox(); bar = new ProgressBar(0); indicator = new ProgressIndicator(0); toolbar.getChildren().add(bar); toolbar.getChildren().add(indicator); button = new Button("Restart"); processLabel = new Label(); processLabel.setFont(new Font("Serif", 36)); box.getChildren().add(toolbar); box.getChildren().add(button); box.getChildren().add(processLabel); Scene scene = new Scene(box); primaryStage.setScene(scene); button.setOnAction(e -> { Task<Void> task = new Task<Void>() { int task = numTasks++; double max = 200; double perc; @Override protected Void call() throws Exception { try { progressLock.lock(); for (int i = 0; i < 200; i++) { System.out.println(i); perc = i/max; // THIS WILL BE DONE ASYNCHRONOUSLY VIA MULTITHREADING Platform.runLater(new Runnable() { @Override public void run() { bar.setProgress(perc); indicator.setProgress(perc); processLabel.setText("Task #" + task); } }); // SLEEP EACH FRAME //try { Thread.sleep(10); // } catch (InterruptedException ie) { // ie.printStackTrace(); // } }} finally { progressLock.unlock(); } return null; } }; // THIS GETS THE THREAD ROLLING Thread thread = new Thread(task); thread.start(); }); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
例子里面用到了Task类,关于Java并发的内容并不是很熟悉,就不深入研究了。
如何结果(kill)掉一个线程?
常见的做法是设置一些条件(loop, exception)来让thread在运行达到一定结果之后终止(自我毁灭)。
- Need program to do something X times/second
- TimerTask可以看做第三种实现线程的方式(extend threads 和 implement Runnable之外)
"Timer和TimerTask可以做为实现线程的第三种方式,前两中方式分别是继承自Thread类和实现Runnable接口。
Timer是一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask。TimerTask是一个抽象类,实现了Runnable接口,所以具备了多线程的能力。" Java线程(五):Timer和TimerTask
原文:http://www.cnblogs.com/zeqli/p/4371221.html