线程与进程
进程是程序的一次动态执行过程,包括代码加载、执行到执行完毕的一个完整过程。
线程是比进程更小的执行单元,是在进程的基础上进一步划分的。多线程是实现并发机制的一种有效手段,所谓多线程指的是一个进程在执行过程中产生多个线程,这些线程可以同时存在、运行。线程一定要依附进程才能够存在。
多线程实现
多线程的实现包括:继承Thread类和实现Runnable(Callable)接口
继承Thread类
java.lang.Thread是一个负责线程操作的类,任何类继承Thread类就成为一个线程的主类,线程启动的主方法需要覆写Thread类中的run()方法实现
线程的执行和进程一样,需要轮流去抢占资源,所以多线程的执行也是多个线程彼此交替执行。多线程的启动唯一方法是Thread类中的start()方法:public void start()
为什么多线程的启动是start()不是run()? |
Thread类中的start()方法不仅要启动多线程的执行代码,还要根据不同的操作系统进行资源分配 |
实现Runnable接口
继承Thread类最大的缺点是单继承问题,Java可以通过Runnable接口实现多线程,线程的主类只需要覆写此方法就可以。多线程的启动是通过Thread类的一个有参构造:public Thread(Runnable target),可以接受一个Runnable接口对象--->new Thread(对象).start()
两种多线程实现方法的区别
从Java实际开发角度来看。肯定是Runnable接口,可以有效避免单继承的局限。
Thread类的定义 |
public class Thread extends Object implements Runnable |
通过Thread类的定义,可以发现Thread类也是Runnable接口的子类。
Runnable接口和Thread类还有一个特点:使用Runnable接口可以更加方便表现出数据共享的概念。
多线程两种实现方式和区别,分别编写程序验证两种实现方式? ● 多线程两种实现方式都需要一个线程的主类,可以实现Runnable类或者继承Thread类,都需要在子类中覆写run()方法,此方法为线程的主方法 ● Thread类是Runnable接口的子类,而且使用Runnable接口可以避免单继承局限,并且更加方便实现数据共享的概念。 程序实现结构如下: | |
Runnable接口 | Thread类 |
class MyThread implements Runnable{ @Override public void run(){ //线程主方法 //线程操作方法 } } | class MyThread extends Thread{ @Override public void run(){ //线程主方法 //线程操作方法 } } |
MyThread mt=new MyThread(); new Thread(mt).start(); | MyThread mt=new MyThread(); mt.start(); |
利用Callable接口实现多线程
Runnable接口虽然可以避免单继承性,但是Runnable接口run()方法不能返回操作结果。Java对于多线程实现提供了一个新的接口:java.util.concurrent.Callable;接口中存在一个call()方法,可以实现线程操作数据的返回,返回的数据类型由Callable接口上的泛型类型动态决定。
Callable类的定义 |
@FunctionalInterface(函数式接口) public interface Callable<V>{ public V call() throws Exception; } |
Thread类中没有定义任何构造方法可以直接接受Callable接口对象实例,由于需要接受call()方法返回值的问题,Java提供了一个新的类:java.util.concurrent.FutureTask<V>,实现了RUnnableFuture接口,而RunnableFuture接口同时实现了Future与Runnable接口
public class FutureTask<V>extends object implements RunnableFuture<V> |
线程的操作状态
任何线程一般包括五种状态:
-
创建:程序中用任何方法创建一个线程对象后,新的线程对象便处于新建状态
- 就绪:调用线程的start()方法就可以启动线程,当线程启动,线程就进入就绪状态
- 运行:当就绪状态的线程被调用并获得处理器资源时,线程就进入运行状态了
- 堵塞:一个正在执行的线程被认为挂起或需要执行耗时的输入输出操作时,将让出CPu并暂时中止自己的执行,进入阻塞状态。调用sleep()、suspend()、wait()等方法,线程将进入堵塞状态
- 终止:调用stop()或run(0方法结束后,就处于终止状态
多线程常用操作方法
线程的命名与取得
每一次线程程序的执行都会是不同的结果,会根据自己的情况进行资源的抢占,要想区分每一个进程,就必须依靠线程的名字。对于线程的名字一般而言会在启动之前进行定义。
public static Thread currentThread() | 取得当前线程对象的方法 |
public Thread(Runnable target,String name) | 实例化线程对象,接受Runnable接口子例化对象,同时设置线程名称 |
public final void setName(String name) | 设置线程名字 |
public final void getName() | 取得线程名字 |
多有的线程都是在进程的基础上划分的,进程在哪里 |
每一个JVM运行就是进程。 用户使用Java指令执行一个类时就表示启动了一个JVM的进程,而主办方只是这个进程上的一个进程而已,当一个类执行完毕后,此进程就会自动消失 每一个JVM进程都至少启动一下两个进程 ● main线程:程序的主要执行,以及启动线程 ● gc线程:负责垃圾收集 |
线程的休眠
线程的休眠让程序执行速度变慢一点:public static void sleep(long millis) throws InterruptedException。休眠单位是毫秒(ms).
线程的优先级
-
最高优先级:MAX_PRIORITY
-
中等优先级:NORM_PRUORITY
- 最低优先级:MIN_PRIORITY