一.继承Thread的线程
1.定义Thread类的子类,并重写该类的run()方法,该run()方法就是代表了线程要完成的任务.因此run方法是线程执行体.
2.创建Thread子类的实例,就是创建了线程对象.
3.调用线程对象的start()方法来启动该线程.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package
org.credo.thread;
/**
* <p>Description:继承Thread类创建线程类. </p>
* @author <a href="zhaoqianjava@qq.com">Credo</a>
*/
public
class
FirstThread
extends
Thread{
private
int
i;
/*
* 重写run()方法,run方法的方法体就是线程的执行体.
*/
public
void
run(){
for
(;i<
10
;i++){
//当线程类继承Thread类时,直接使用this即可获取当前线程
//Thread对象的getName()返回当前线程的名字
//因此可以直接调用getName()方法返回当前线程的名字
System.out.println(getName()+
" "
+i);
}
}
public
static
void
main(String[] args) {
for
(
int
i=
0
;i<
10
;i++){
//调用Thread的currentThread()方法获得当前线程
System.out.println(Thread.currentThread().getName()+
" "
+i);
if
(i==
2
){
//创建并启动第一个线程,使用start方法启动线程.
new
FirstThread().start();
//创建并启动第二个线程
new
FirstThread().start();
}
}
}
}
|
- Thread.currentThread():currentThread()是Thread类的静态方法,该方法总是返回当前正在执行的线程对象.
- getName():该方法是Thread的实例方法,该方法返回调用该方法的线程名字.
我们看下线程的输出情况.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
main
0
main
1
main
2
Thread-
0
0
Thread-
0
1
Thread-
0
2
Thread-
0
3
Thread-
0
4
Thread-
1
0
main
3
Thread-
1
1
Thread-
0
5
Thread-
1
2
main
4
Thread-
1
3
main
5
Thread-
0
6
main
6
Thread-
1
4
main
7
Thread-
0
7
main
8
Thread-
1
5
main
9
Thread-
0
8
Thread-
0
9
Thread-
1
6
Thread-
1
7
Thread-
1
8
Thread-
1
9
|
因此就可以有个结论:使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量.
二.实现Runnable接口创建线程类
实现Runnable接口来创建并启动多线程的步骤如下:
1.定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体.
2.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象.
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
org.credo.thread;
public
class
FirstRunnable
implements
Runnable{
private
int
i;
public
void
run(){
for
(;i<
10
;i++){
//当线程类实现Runnable接口时,
//如果想获取当前线程,只能用Thread.currentThread()方法.
System.out.println(Thread.currentThread().getName()+
" "
+i);
}
}
public
static
void
main(String[] args) {
for
(
int
i=
0
;i<
10
;i++){
System.out.println(Thread.currentThread().getName()+
" "
+i);
if
(i==
2
){
FirstRunnable fr=
new
FirstRunnable();
//通过new Thread(target,name)方法创建新线程
new
Thread(fr,
"newThread11"
).start();
new
Thread(fr,
"newThread22"
).start();
}
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
main
0
main
1
main
2
main
3
main
4
newThread11
0
newThread22
0
newThread22
2
main
5
main
6
main
7
main
8
main
9
newThread22
3
newThread22
4
newThread11
1
newThread11
6
newThread22
5
newThread11
7
newThread22
8
newThread11
9
|
三:使用Callable和Future创建线程
前面可以看到,通过实现Runnable接口创建多线程的时候,Thread类的作用就是把run()方法包装成线程执行体.
那么是否可以把任意方法都包装成线程执行体呢?
Java貌似不可以,但C#貌似可以.
因此从java5开始,java提供了Callable接口,该接口其实就是Runnable接口的增强版.Callable接口提供了一个call()方法可以作为线程执行体,但call方法比run()方法功能更强大.
- call方法可以有返回值.
- call方法可以声明抛出异常.
因此我们可以提供一个callable对象作为Thread的target.而该线程的线程执行体就是该Callable对象的call方法.但问题来了,callable是java5新增的一个并不是runnable接口的子接口,因此不能直接作为Thread的target,而且call方法还有一个返回值,call方法并不是直接调用.它是作为线程执行体被调用的.那么如果最后获取其值呢?
Java提供了Future接口来代表Callable接口里的call方法的返回值,并为future提供了一个FutureTask实现类.该类实现了Future接口,并且实现了Runnable接口--它可作为Thread类的target.
步骤基本如下:
1.创建Callable接口的实现类,并实现call()方法,该call方法将作为线程执行体.能抛异常,能有返回值.
2.创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值.
3.使用FutureTask对象作为Thread对象的target创建并启动线程.
4.调用FutureTask对象的get()方法获取子线程的返回值.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package
org.credo.thread;
import
java.util.concurrent.Callable;
import
java.util.concurrent.FutureTask;
public
class
CallableAndFuture
implements
Callable<Integer>{
public
static
void
main(String[] args) {
CallableAndFuture caf=
new
CallableAndFuture();
FutureTask<Integer> future=
new
FutureTask<Integer>(caf);
for
(
int
i=
0
;i<
100
;i++){
System.out.println(Thread.currentThread().getName()+
"的I的值是:"
+i);
if
(i==
20
){
new
Thread(future,
"有返回值的线程"
).start();
}
}
try
{
System.out.println(
"子线程的返回值:"
+future.get());
}
catch
(Exception e) {
e.printStackTrace();
}
}
@Override
public
Integer call()
throws
Exception {
int
i=
0
;
for
(;i<
100
;i++){
System.out.println(Thread.currentThread().getName()+
"的I的值为:"
+i);
}
return
i;
}
}
|
总结:掌握主线,支线的API查阅也就知道了.一般情况下不去使用继承Thread.太蛋疼了那样.就用Runnable和callable.