公众号程序猿冰冰,分享java干货
Java 给多线程编程提供了内置的支持。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
1.进程 & 线程
1.1进程
1.进程:正在运行的应用长须
2.是系统进行资源分配和调用的独立单位
3.每一个进程都有它自己的内存空间和系统资源
1.2. 线程
1.线程:是进程中的单个顺序控制流,是一条执行路径
2.单线程:一个进程如果只有一条执行路径,则称为单线程程序
3.多线程:一个进程如果有多条执行路径,则称为多线程程序
一个线程的生命周期
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
下图显示了一个线程完整的生命周期。
在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态
新建状态:使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态:当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行
运行状态:如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态
阻塞状态:当处于运行状态的线程失去所占用资源之后,便进入阻塞状态
死亡状态:线程在run()方法执行结束后进入死亡状态。此外,如果线程执行了interrupt()或stop()方法,那么它也会以异常退出的方式进入死亡状态。
可以对照上面的线程状态流转图来看具体的方法,这样更清楚具体作用:
1.start()
启动当前线程, 调用当前线程的run()方法
2.run()
通常需要重写Thread类中的此方法, 将创建的线程要执行的操作声明在此方法中
3.join()
在线程a中调用线程b的join(), 此时线程a进入阻塞状态,直到线程b完全执行完以后, 线程a才结束阻塞状态
4.sleep
让线程睡眠指定的毫秒数,在指定时间内,线程是阻塞状态
5.wait()
一旦执行此方法,当前线程就会进入阻塞,一旦执行wait()会释放同步监视器。
6.sleep()和wait()的异同
相同点:
两个方法一旦执行,都可以让线程进入阻塞状态。
不同点:
1.两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
2.调用要求不同:sleep()可以在任何需要的场景下调用。wait()必须在同步代码块中调用。
线程的优先级
每一个线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
Java线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY) - 10 (Thread.MAX_PRIORITY )。
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
创建线程的三种方法
Java 提供了三种创建线程的方法:
1.通过实现 Runnable 接口
定义MyRunnable类实现Runnable接口;
实现run()方法,编写线程执行体;
创建线程对象,调用start()方法启动线程。
2.通过继承 Thread 类本身
自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
【注意】:线程开启不一定立即执行,由CPU安排调度。
3.通过 Callable 和 Future 创建线程(了解)。
1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
小结
1.继承Thread类
(1)子类继承Thread类具备多线程能力
(2)启动线程:子类对象.start()
(3)不建议使用:避免OOP单继承局限性
2.实现Runnable接口
(1)实现接口Runnable具有多线程能力
(2)启动线路:传入目标对象 Thread对象.start()
(3)推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
3.多线程的使用
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。
通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。
请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!
java多线程就分享到这里,希望对大家有帮助!
END
,