创建多线程程序的第一种方式:继承Thread类
Java使用 java.lang.Thread 类代表线程,所有的线程对象必须是Thread类或其子类的实例,即我们想要实现多线程程序,就必须继承Thread 类。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。
实现步骤: 1.创建一个Thread类的子类 2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么) 3.创建Thread类的子类对象 4.调用Thread类中的方法sort方法,开启新的线程,执行run方法 void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 结果是两个线程并发地运行;当前线程(main线程)和另一个线程(创建的新线程,执行其 run 方法)。 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。 注:java程序属于抢占式调度,即哪个线程的优先级高就优先执行,同一个优先级就随机选择一个执行。
代码演示:
//1.创建一个Thread类的子类
public class MyThreadDemo1 extends Thread {
//2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)
@Override
public void run() {
for (int i = 0; i < 5; i++){
System.out.println("run ; " + i);
}
}
}
//创建主类
public class CreateThreadDemo1 {
public static void main(String[] args) {
//3.创建Thread类的子类对象
MyThreadDemo1 mt = new MyThreadDemo1();
//4.调用Thread类中的方法sort方法,开启新的线程,执行run方法
mt.start();
//主线程中的for循环
for (int i = 0; i < 5; i++){
System.out.println("main ; " + i);
}
}
}
输出结果:
run ; 0
main ; 0
main ; 1
run ; 1
main ; 2
main ; 3
main ; 4
run ; 2
run ; 3
run ; 4
根据结果可以看出,由于java程序属于抢占式调度,所以主线程和新线程之间进行抢夺式执行,并且每次执行的输出结果都不一样。
创建多线程程序的第二种方式:实现Runnable接口
通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个执行目标。所有的多线程 代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。 在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread 对象的start()方法来运行多线程代码。
实现步骤: 1.创建一个Runnable接口的实现类 2.在实现类中重写Runnable接口的run方法,设置线程方法 3.创建一个Runnable接口的实现类对象 4.创建Thread对象,构造方法中传递Runnable接口的实现类对象 5.调用Thread类中的start方法,开启新的线程执行run方法
代码演示:
/*
java.lang.Runnable
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参方法。
java.lang.Thread类的构造方法:
Thread(Runnable target) 分配新的Thread对象。
Thread(Runnable target, String name) 分配新的Thread对象。
*/
//1.创建一个Runnable接口的实现类
public class RunnableImpl implements Runnable{
//2.在实现类中重写Runnable接口的run方法,设置线程方法
@Override
public void run() {
//新的线程中的for循环
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
//创建主类
public class CreateThreadDemo2 {
public static void main(String[] args) {
//3.创建一个Runnable接口的实现类对象
RunnableImpl r = new RunnableImpl();
//4.创建Thread对象,构造方法中传递Runnable接口的实现类对象
Thread t = new Thread(r); //打印线程名称
//5.调用Thread类中的start方法,开启新的线程执行run方法
t.start();
//主线程中的for循环
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
输出结果:
Thread-0-->0
main-->0
main-->1
Thread-0-->1
main-->2
main-->3
main-->4
Thread-0-->2
Thread-0-->3
Thread-0-->4
实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现 Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程 编程的基础。
Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。 而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。
Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
实现Runnable接口创建多线程程序的好处: 1.避免了单继承的局限性 一个类只能继承一个类,类继承了Thread类就不能继承其他的类 实现了Runnable接口,还可以继承其他的类,实现其他的接口 2.增强了程序的扩展性,降低了程序的耦合性(也就是解耦) 实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦) 实现类中,重写了run方法,用来设置线程任务 创建Thread类对象,调用start方法,用来开启新线程 3.线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
扩充:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用 java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进 程。