创建和启动线程
概述
Java语言的JvM允许程序运行多个线程,使用 java.1ang.Thread 类代表 线程,所有的线程对象都必须是
Thread类或其子类的实例。
Thread类的特性
- 每个线程都是通过某个特定Thread对象的
run()方法来完成操作的,因此把run()方法体称为线程执行体。 - 通过该Thread对象的start)方法来启动这个线程,而非直接调用
run() - 要想实现多线程,必须在主线程中创建新的线程对象。
Thread().start() 会调用 run() 方法,在源码中会调用 start0() 一个 native 的方法,后面是操作系统发挥作用。
方式1:继承 Thread 类
创建一个继承 Thread 的子类
重写 Thread 类的 run() ,将此线程要做的操作声明在此方法体中
创建当前 Thread 的子类的对象
通过对象调用 start() 方法,start() 的两个作用,一个是启动线程一个是调用run()方法问题1:是否可以直接调用
run()替换start()的调用,实现分线程的调用?
使用 run() 的调用程序可以运行,但是从整体看此时就不满足并发发生的情景,而是单线程发生的场景。问题2:基于同一个对象再次运行 start() 方法,是否可以再次创建一个新的线程?
不会,从下面的代码中可以看到此时会报一个异常
if (holder.threadStatus != 0)
throw new IllegalThreadStateException();
要开启一个新的线程,就要创建一个新的线程对象。
示列:
class PrintNumber extends Thread{
public void run(){
for (int i = 1; i <= 10000; i++) {
if (i % 2 != 0){
System.out.println(i);
}
}
}
}
public class Main {
public static void main(String[] args) {
PrintNumber t1 = new PrintNumber();
t1.start();
for (int i = 1; i < 10000; i++) {
if( i % 2!= 0 ){
System.out.println(i + "是一个奇数 main");
}
}
}
}
==>
--snip--
543
8545
8547
8549
8551
8553
3439是一个奇数 main
3441是一个奇数 main
3443是一个奇数 main
3445是一个奇数 main
3447是一个奇数 main
3449是一个奇数 main
3451是一个奇数 main
3453是一个奇数 main
3455是一个奇数 main
3457是一个奇数 main
8555
8557
8559
8561
--snip--
PrintNumber 是一个继承 Thread 的类,Main类中实例化 PrintNumber 类,在主类中也创建一个线程任务。
Thread.currentThread().getName()
这个方法用于打印当前线程的名字。
方式2:实现 Runnable 接口
由于继承Thread类具有一定的局限性(java的单继承不能继承其他的类),这就需要使实现 Runnable() 接口的方式。
创建一个实现Runnable接口的类
实现接口中的run()-->将此线程要执行的操作,声明在此方法体中
创建当前实现类的对象
将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例
Thread类的实例调用 start()为什么 new Thread(Runnable对象).run() 调用的是Runnable对象的方法。而没有调用 Thread对象的run()方法?
对于 Thread类:
private Runnable target;
public void run(){
if (targrt != null){
targrt.run();
}
}
class EvenNumberPrint implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
}
public class Main {
public static void main(String[] args) {
EvenNumberPrint evenNumberPrint = new EvenNumberPrint();
new Thread(evenNumberPrint).start();
for (int i = 1; i <= 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
}
==>
--snip--
main75
Thread-084
main77
Thread-086
main79
Thread-088
main81
main83
--snip--
方式3:匿名
使用匿名实现类的匿名对象。
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
对比两种方式
共同点:
- ① 启动线程使用的都是 Thread 类中定义的方法
- ② 创建的线程对象都是 Thread 类或其子类的实例。
不同点:
- 一个是类的继承,一个是接口的实现
建议使用 Runnable 接口的方式,好处:实现的方式避免类单继承的实现性。更适合处理有共享数据的问题,如 evenNumberPrint 对象可以被其他的 Thread 类作为参数共享。
联系:
public class Thread implemnets Runnable
代理模式。

浙公网安备 33010602011771号