目录
三 、通过 Thread 类 和 Runnable 接口实现多线程的区别
一 、进程 与 线程
进程是程序的一次动态的执行过程。多进程系统可以同时运行多个进程(也就是程序),而线程是比进程更小的执行单位,比如运行一个听歌的软件(进程),播放歌曲就是其中一个线程,搜索歌曲也是一个线程,浏览评论也是一个线程
多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在,同时运行,所以一个进程可能包含了多个同时执行的线程。
多线程是实现并发机制的一种有效手段
二 、Java中多线程的实现
在Java中要想实现多线程代码有两种方法:
【1】继承 Thread 类
【2】实现 Runnable 接口
1 、继承 Thread 类实现多线程
Thread 类是在Java.lang包中定义,一个类如果继承了 Thread 类,此类就称为多线程操作类,在Thread子类中,必须明确地覆写 run() 方法,并通过 start() 方法启动线程
class MyThread extends Thread{ //继承Thread类
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){ //覆写Thread类中的run()方法
for (int i=0; i<10; i++){
System.out.println(name + "运行,i = " + i);
}
}
}
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.start(); //调用start()方法启动线程
mt2.start(); //调用start()方法启动线程
}
}
程序运行结果(可能的一种结果):
从程序的运行结果可以发现,两个线程交替运行,哪个线程对象抢到了CPU资源,哪个线程就可以运行,所以程序每次的运行结果都不一样
提问:为什么启动线程必须通过start()方法启动,而不能直接调用 run() 方法呢?
回答:由于多线程的实现需要依靠底层操作系统得支持,start() 方法除了会调用run() 方法,还有一些调用本机操作系统的函数。另外,一个线程对象只能调用一次start()方法,调用一次便可以启动多线程,如果调用多次,则会抛出异常
继承 Thread 类可以实现多线程,但会受到单继承局限的影响,所以,还可以通过实现Runnable接口实现多线程
2 、实现 Runnable 接口实现多线程
查阅JDK文档发现,Runnable 接口只定义了一个 run() 方法
要想启动一个多线程必须使用 start() 方法完成,那么此时该如何启动多线程呢?
查阅JDK文档的Thread类发现其有构造方法可以接收Runnable的子类实例对象,所以就可以依靠此点启动多线程
实现Runnable接口,通过Thread类启动多线程
class MyThread implements Runnable{ //实现Runnable接口
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){ //覆写Runnable接口中的run()方法
for (int i=0; i<10; i++){
System.out.println(name + "运行,i = " + i);
}
}
}
public class RunnableDemo01 {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程C"); //实例化Runnable子类对象
MyThread mt2 = new MyThread("线程D"); //实例化Runnable子类对象
Thread t1 = new Thread(mt1); //实例化Thread类对象
Thread t2 = new Thread(mt2); //实例化Thread类对象
t1.start(); //启动线程
t2.start(); //启动线程
}
}
程序运行结果(可能的一种结果):
三 、通过 Thread 类 和 Runnable 接口实现多线程的区别
使用 Thread 类实现多线程时无法实现资源共享,而实现 Runnable 接口实现多线程可以实现资源共享
1 、继承 Thread 类不能资源共享
class MyThread extends Thread{
private int ticket = 5; //一共有5张票
public void run(){
for (int i=0; i<100; i++){
if (ticket>0){ //判断是否有余票
System.out.println("卖票:ticket = " + ticket--);
}
}
}
}
public class ThreadDemo02 {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
mt1.start();
mt2.start();
mt3.start();
}
}
程序运行结果:
从程序的运行结果可以发现,每个线程都各自卖自己的5张票,没有达到资源共享
2 、实现 Runnable 接口实现资源共享
class MyThread implements Runnable{
private int ticket = 5; //一共5张票
public void run(){
for (int i=0; i<100; i++){
if (ticket>0){ //判断是否有余票
System.out.println("卖票:ticket = " + ticket--);
}
}
}
}
public class RunnableDemo02 {
public static void main(String[] args) {
MyThread mt = new MyThread();
//启动3个线程
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
程序运行结果:
3个线程一共卖了5张票
实现 Runnable 接口相对于继承 Thread类来说,有如下优势:
【1】适合多个相同程序代码的线程去处理同一资源的情况
【2】可以避免由于Java的单继承特性带来的局限
【3】增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的
所以在开发中建议使用 Runnable 接口实现多线程