前言
线程,英文Thread。在java中,创建线程的方式有三种:
1、Thread
2、Runnable
3、Callable
在详细介绍下这几种方式之前,我们先来看下Thread类和Runnable接口。
Runnable接口
接口中只有一个run()方法,等待实现类去实现。
-
package java.lang;
-
@FunctionalInterface
-
public
interface Runnable {
-
-
public abstract void run();
-
}
Thread类
该类实现了Runnable接口,也提供了很多其他的方法,如yield(),join()等
-
package java.lang;
-
public
-
class Thread implements Runnable {
-
//获取当前线程
-
public static native Thread currentThread();
-
public static native void yield();
-
//一系列的构造函数
-
public Thread(Runnable target, String name) {
-
init(
null, target, name,
0);
-
}
-
public Thread(ThreadGroup group, String name) {
-
init(group,
null, name,
0);
-
}
-
/*调用该方法时,jvm会调用run方法
-
*Causes this thread to begin execution; the Java Virtual Machine
-
* calls the run method of this thread.
-
*/
-
public synchronized void start() {
-
-
if (threadStatus !=
0)
-
throw
new IllegalThreadStateException();
-
-
group.add(
this);
-
-
boolean started =
false;
-
try {
-
start0();
-
started =
true;
-
}
finally {
-
try {
-
if (!started) {
-
group.threadStartFailed(
this);
-
}
-
}
catch (Throwable ignore) {
-
-
}
-
}
-
}
-
-
}
一、实现Runnable接口
-
public
class i_Runnable {
-
-
/**
-
* 主线程main方法
-
* @param args
-
*/
-
public static void main(String[] args) {
-
for (
int i =
0; i <
100; i++) {
-
System.out.println(Thread.currentThread().getName() +
"====" + i);
-
if (i ==
20) {
-
RunnableThreadTest rtt =
new RunnableThreadTest();
-
//子线程
-
new Thread(rtt,
"new Thread[1]====").start();
-
//new Thread(rtt, "新线程2").start();
-
}
-
}
-
-
}
-
/**
-
* RunnableThreadTest实现Runnable接口
-
* @author YANG
-
*
-
*/
-
static
class RunnableThreadTest implements Runnable {
-
private
int i;
-
-
@Override
-
public void run() {
-
for (i =
0; i <
100; i++) {
-
System.out.println(Thread.currentThread().getName() +
" " + i);
-
}
-
-
}
-
-
}
-
}
执行结果:
注意:
** 执行结果只截取了部分内容。
** 如果RunnableThreadTest类前不加static,会报错No enclosing instance of type i_Runnable is accessible. Must qualify the allocation with an enclosin。因为只有内部类修饰为静态时,才可以在静态类方法(main方法)中调用该类的成员变量和方法。
二、继承Thread类
-
public
class a_Thread {
-
public static void main(String[] args) {
-
Runner1 r=
new Runner1();
-
r.start();
//已经有thread 不需要new,直接调用start即可。
-
-
-
for (
int i =
0; i <
100; i++) {
-
System.out.println(
"main Thread:"+i);
-
}
-
}
-
-
//Runner1继承Thread类,重写run方法
-
static
class Runner1 extends Thread{
-
@Override
-
public void run() {
-
-
for (
int i =
0; i <
100; i++) {
-
System.out.println(
"Runner1:"+i);
-
}
-
-
}
-
-
}
-
}
分析:换成run()方法之后,就变成了普通的方法调用,只有一个主线程,没有子线程。
执行结果:为了方便显示,我们将循环次数改为10。
-
Runner1:
0
-
Runner1:
1
-
Runner1:
2
-
Runner1:
3
-
Runner1:
4
-
Runner1:
5
-
Runner1:
6
-
Runner1:
7
-
Runner1:
8
-
Runner1:
9
-
main Thread:
0
-
main Thread:
1
-
main Thread:
2
-
main Thread:
3
-
main Thread:
4
-
main Thread:
5
-
main Thread:
6
-
main Thread:
7
-
main Thread:
8
-
main Thread:
9
三、实现Callable接口
前面两种方式是传统的线程技术中的内容,第三种方式Callable和Future是jdk1.5之后新增的。我们先来补充点东西,看看这种方式与之前的方式有什么联系。
-
//实现Callable接口
-
public
class j_CallableTest implements Callable<String> {
-
public static void main(String[] args) {
-
j_CallableTest test=
new j_CallableTest();
-
FutureTask<String> ft=
new FutureTask<>(test);
-
-
for (
int i =
0; i <
100; i++) {
-
System.out.println(Thread.currentThread().getName()+
" i的值为="+i);
-
if(i==
20){
-
new Thread(ft,
"子线程").start();
-
}
-
}
-
}
-
-
//重写call方法
-
@Override
-
public String call() throws Exception {
-
int i =
0;
-
String reString =
"";
-
for (; i <
100; i++) {
-
reString = Thread.currentThread().getName() +
" " + i;
-
System.out.println(reString);
-
}
-
return reString;
-
}
-
}
从上面可以看到,new Thread的方式还是用的public Thread(Runnable target, String name); 说明FutureTask也是Runnable类型的,他们之间的关系可以从下图中看出来。
那么,使用Callable和Future的方式有什么特点呢?
我们从他们的定义来看,Callable接口中只有一个方法,返回值为V。前两种方式都是返回void。
-
@FunctionalInterface
-
public
interface Callable<V> {
-
/**
-
* Computes a result, or throws an exception if unable to do so.
-
*
-
* @return computed result
-
* @throws Exception if unable to compute a result
-
*/
-
V call() throws Exception;
-
}
小结:
1、接口实现更灵活,java不支持多继承。在这方面,Runnable和Callable更有优势。
2、返回值问题。Runnable和Thread都不能有返回值,但Callable可以,而且支持多种类型的数据。
就这两点来看,新增的Callable和Future的实现方式优势十分明显啊。但是追到原理,其实这三种都可以归结为一种方式。