博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程知识总结
阅读量:3777 次
发布时间:2019-05-22

本文共 4164 字,大约阅读时间需要 13 分钟。

进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

详细解释:

程序:为了完成特定任务,用某种语言编写的一组指令集合(一组静态代码)
进程:运行中的程序,系统调度与资源分配的一个独立单位,操作系统会 为每个进程分配一段内存空间!程序的依次动态执行,经历代码的加载,执行, 执行完毕的完整过程!
线程:比进程更小的执行单元,每个进程可能有多条线程,线程需要放在一个 进程中才能执行,线程由程序负责管理,而进程则由系统进行调度!
多线程的理解:并行执行多个条指令,将CPU时间片按照调度算法分配给各个 线程,实际上是分时执行的,只是这个切换的时间很短,用户感觉到"同时"而已!

线程的创建有三种:

1、继承Thread类代表线程
定义Thread类的子类,并重写run()方法,run()方法称为线程的执行体;
创建Thread类的子类的实例,即创建线程的对象;
调用线程对象的start()方法启动线程。
代码示例:

package thread;public class TestThread {	public static void main(String[] args) {		SubThread1 st1 = new SubThread1();		SubThread1 st2 = new SubThread1();		st1.start();		st2.start();	}}class SubThread1 extends Thread{	public void run(){		for(int i = 0;i< 14;i++) {			if(i % 2 == 0) {				System.out.println(Thread.currentThread().getName()+" "+i);			}		}	}}

运行结果:

Thread-0 0Thread-1 0Thread-1 2Thread-1 4Thread-0 2Thread-1 6Thread-0 4

2、实现Runnable接口创建线程:

定义Runnable接口实现类,并重写run()方法;
创建Runnable实现类的实例,并将实例对象传给Thread类的target来创建线程对象;
调用线程对象的start()方法启动线程。
代码示例:

package thread;public class TestRunnable {         public static void main(String[] args) {			SubThread2 st = new SubThread2();			new Thread(st,"thread1").start();			new Thread(st,"thread2").start();		}}class SubThread2 implements Runnable{	public void run() {		for(int i = 0;i < 8; i++) {			if (i % 2 == 0) {				System.out.println(Thread.currentThread().getName()+" "+i);			}		}		}}

结果:

thread1:0thread2:0thread2:2thread2:4thread2:6thread1:2

3、使用Callable接口和Future接口创建线程:

定义Callable接口实现类,指定返回类型,并重写call()方法;
创建Callable接口实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
使用FutureTask对象作为Thread对象的target创建并启动新线程;
调用FutureTask 对象的get()方法来获得子线程执行结束后的返回值。

代码示例:

package thread;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class TestCallable {         public static void main(String[] args) {			Callable
myCallable = new SubThread3(); FutureTask
ft = new FutureTask
(myCallable); for(int i = 0;i < 4;i ++) { System.out.println(Thread.currentThread().getName()+" "+i); if(i % 2 == 1) { Thread thread = new Thread(ft); thread.start(); } } System.out.println("主线程for循环执行完成"); try { int sum = ft.get(); System.out.println("sum ="+sum); }catch(InterruptedException e){ e.printStackTrace(); }catch(ExecutionException e) { e.printStackTrace(); } }}class SubThread3 implements Callable
{ private int i = 0; public Integer call()throws Exception{ int sum = 0; for(i = 0;i<3;i++) { System.out.println(Thread.currentThread().getName()+" "+i); sum += i; } return sum; }}

结果:

main 1main 2main 3主线程for循环执行完成Thread-1 0Thread-1 1Thread-1 2sum =3

总结:

创建线程必须要通过Thread类的实例或Thread类子类的实例,然后调用start()方法启动线程,上述三种方式可以分为两种:1是调用无参的构造函数Thread()来实例化对象;2、3是调用Thread(Runnable target)构造方法,其中参数为Runnable类的实例化对象,在3中使用了FutureTask(FutureTask实现了Runnable接口),因此可以看做FutureTask的实例化对象是Runnable类型的。

创建线程的三种方式的对比:

  1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

  2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

  3. 使用Callable 接口的方式有返回值,可以抛出异常。

    在这里插入图片描述
    线程的生命周期和状态转换
    在这里插入图片描述
    1、新建状态:
    使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。此时线程对象在堆空间中分配了一块内存,但还不能运行。

2、就绪状态:

当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,java虚拟机会 为它创建调用栈和程序计数器,处于这个状态 的线程位于可运行池中,等待获得CPU的使用权。

3、运行状态:

如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态,每个CPU只能被一个线程占用。只有处于运行状态的线程才可以转换到运行状态,处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

4、阻塞状态:

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用CPU等资源之后,该线程就从运行状态进入阻塞状态,进入阻塞状态java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态才有可能分配到CPU,再次进入运行状态。可以分为三种:

等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

5、死亡状态:

一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。如改线程的run()方法再次执行完成,线程正常结束;线程抛出异常或错误;调用线程的stop()方法结束该线程。一旦线程转换为死亡状态就不能运行且不能转换为其他状态。

线程的调度:

由于一个CPU只能执行一个线程,在运行池中会有多个处于就绪状态的线程在等待CPU,Java虚拟机负责线程的调度,即按照特定的机制为多个线程分配CPU使用权。调度模型分为分时调度模型和抢占式调度模型两种。

转载地址:http://hypvn.baihongyu.com/

你可能感兴趣的文章
web开发之BaseServlet的使用
查看>>
初识Maven
查看>>
Maven分模块构建项目
查看>>
MyBatis初识
查看>>
MyBatis【进阶详解】
查看>>
面试题集锦(七)
查看>>
注解开发——Spring整合dao/service/web
查看>>
架构的演进
查看>>
Elastic-Job的基础使用
查看>>
策略过滤器的灵活性分析
查看>>
POI的使用
查看>>
Anaconda和PyCharm的下载、安装和配置
查看>>
Mockito单元测试简述
查看>>
GUAVA的常用方法汇总
查看>>
装饰器和门面设计模式介绍
查看>>
创建型模式——克隆模式
查看>>
JVM关闭和Hook钩子
查看>>
线程中断处理
查看>>
消息队列积压问题处理
查看>>
并行流使用注意事项
查看>>