线程是Java中的一个重要学习内容,有一段时间没用到,最近重温了一下。写点东西记录一下。
什么是线程?
线程是指程序在执行过程中,能够执行程序程序代码的一个执行单元。在Java语言中,线程有四种状态:运行、就绪、挂起和结束。
为什么要使用多线程
- 使用多哦线程可以减少程序的相应时间。
- 多CPU或多核计算机本身就具有执行多线程的能力。
- 与进程相比,线程的创建和切换开销更小。
- 使用多线程能简化程序的结构,使程序便于维护和理解。一个非常复杂的进程可以分成多个线程来执行。
基本的线程机制
在使用线程时,CPU将轮流给每个任务分配其占用时间。每个任务都觉得自己在一直占用着CPU,但事实上CPU时间是划分成片段分配给所有的任务。线程可以使你从这个层次抽身出来。
注意:当系统使用时间切片机制时,CPU轮流给每个任务分配时间,例如Windows(线程优先级和时间片轮转调度)操作系统。但有些操作系统采用FIFO模型,除非有高优先级的线程被唤醒,否则当前线程将一直运行,直至阻塞或终止。
如何实现Java多线程
继承Thread类,重写run()方法
Thread 本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,
启动线程的唯一方法就是通过Thread类的start()方法。start()方法是一个native(本地)方法,它将启动一个新线程,并执行一个run()方法(Thread中提供的run()方法是一个空方法)。
这种方式通过自定义直接继承Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法。
调用start()方法后并不是立即执行多线程代码,而是使得该线程变成可运行态,什么时候运行多线程是由CPU调度决定的
1 | class MyThread extends Thread{ |
实现Runnable接口,并实现该接口的run()方法
主要步骤:
1) 自定义类并实现Runnable接口,并实现run()方法。
2) 创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象。
3) 调用Thread的start()方法。
1 | class MyThread implements Runnable{ |
以上两种是实现多线程最常用的方法。
其实不管是通过继承Thread类还是通过使用Runnable接口来实现多线程的方法,最终还是通过Thread的对象的API来控制线程的。
实现Callable接口,重写call()方法
Callable接口实际上是属于Executor框架的功能类,Callable接口与Runnable接口的功能类类似,但提供了比Runnable更强大的功能,主要表现在以下三点:
1)Callable可以在任务结束后提供一个返回值,Runnable无法提供这个功能。
2)Callable中的call()方法可以抛出异常,而Runnable的run()方法无法抛出异常。
3)运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,可以使用Future来监视目标线程调用call()方法的情况,当调用Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法结束返回结果。
1 | public class CallableAndFuture{ |
上述程序的输出结果为:
以上3中方式中,前两种方式线程执行完后都没有返回值,只有最后一种带有返回值的,但是当需要使用多线程时,一般最好是使用实现Runnable接口的方式。
因为Thread类定义的多中方法可以被派生类使用或者重写。但是只有run()方法是必须被重写的,在run()方法中实现了这个线程的主要功能。