多线程的简述

1. 程序, 进程, 线程的概念


个人电脑: CPU 单个, 双核, CPU的时间分片, 抢占式

程序: 是为了完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码。

进程: 运行的程序,表示程序一次完整的执行, 当程序运行完成, 进程也就结束了。

因此,每个独立执行的程序称为进程。

每个进程都有自己独立的内存空间, 进制之间的通信很困难

 * 在操作系统中进程是进行系统资源分配、调度和管理的最小单位,进程在执行过程中拥有独立的内存单元。比如:Windows采用进程作为最小隔离单位,每个进程都有自己的数据段、代码段,并且与别的进程没有任何关系。因此进程间进行信息交互比较麻烦(每个进程都有独立的内存空间,进程之间的通讯很难)。


为了解决进程调度资源的浪费,为了能够共享资源,出现了线程。

线程: 线程是CPU调度和分派的基本单位, 一个进程中,可以同时有多条执行链路, 这些执行链路称为线程, 线程是比进程更小的执行单位, 同一个进程多个线程共享这个进程的内存资源:多个线程共享内存,从而极大地提高了程序的运行效率。

JVM内存模型

 多线程的简述_第1张图片

 每个线程都有自己的栈和程序计数器,多线程共享内存空间(方法区和堆)

进程与线程的关系和区别:

进程包含线程, 一个进程包含多个线程, 操作系统是以进程为单位的,而进程是以线程为单位的, 一个进程最小必须包含一个线程(主线程,main线程)。

运行main()方法的时候, 创建了一个main线程

一个进程死亡了, 这个进程中所有的线程死亡

线程销毁,进程未必会关闭

多线程:

多线程:是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,形成多条执行线。

不管计算机上是一个进程还是多个进程,也不管是一个线程还是多个线程,CPU只有一块,要实现多线程,实际上都需要在一个CPU上完成资源的调度。例如:在某一段时间内只允许A线程操作,而在另外一段时间内,CPU就让给了其他线程,此时需要一个时间片的轮转算法,进行资源的调度

多线程的好处:可以更高效地利用CPU资源,同时,让固定流程的程序更加灵活;

注意:多个线程之间,谁先抢占到资源,谁就先执行

多线程的应用范围很广。在一般情况下,程序的某些部分同特定的事件或资源联系在一起,同时又不想为它而暂停程序其它部分的执行,这种情况下,就可以考虑创建一个线程,令它与那个事件或资源关联到一起,并让它独立于主程序运行。通过使用线程,可以避免用户在运行程序和得到结果之间的停顿,还可以让一些任务(如打印任务)在后台运行,而用户则在前台继续完成一些其它的工作。总之,利用多线程技术,可以使编程人员方便地开发出能同时处理多个任务的功能强大的应用程序

提到多线程就会牵扯到并行与并发,这里简述一下:

并行: 多CPU执行各种不同任务,

并发: 一个CPU执行不同的任务(多个线程)

因此判断多线程速度快吗,要看CPU的核数,个数。

java实现多线程

Java是少数的几种支持“多线程”的语言之一。大多数的程序语言只能循序运行单独一个程序块,但无法同时运行不同的多个程序块。Java的“多线程”恰可弥补这个缺憾,它可以让不同的程序块一起运行,如此一来可让程序运行更为顺畅,同时也可达到多任务处理的目的。


在jdk.1.5之前: 创建线程的方式: 两种:

  • 继承Thread类

  • 实现Runnable接口

在JDK1.5之后: 多加了两种:

  • 实现 Callable接口

  • 线程池

第一种方式:继承Thread

  1. 编写一个类继承Thread,该类是线程类

  2. 重写run(), 编写该线程需要完成的任务

  3. 创建线程类对象

  4. 调用start()方法,启动线程

public class threadDemo extends Thread{

    public threadDemo(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println("我是一个线程,我开始执行了");
    }

    public static void main(String[] args) {
        threadDemo t1 = new threadDemo("t1");
        threadDemo t2 = new threadDemo("t2");
        t1.start();
        t2.start();
    }
}

多线程的简述_第2张图片

 注意:

  1. 线程启动,一定是调用start() , 不是调用run(), 如果直接调用run() ,只是方法的调用,没有创建线程

  2. 一个线程一旦启动,就不能重复启动

多线程的简述_第3张图片

第二种方式: 实现Runnable接口

启动线程: 都必须借助Thread的start()

Runnable实现类: 就是一个线程的任务类

多线程的简述_第4张图片

 

继承Thread与Runnable接口的区别:

  1. 继承Thread类, 这个线程类就不能再继承其他类, 实现Runnable接口, 可以再继承其他类

  2. 实现Runnable接口, 可以让多个线程共享这个Runnable的实现类对象

  3. 继承Thread类,启动简单, 实现Runnable接口, 必须依赖Thread类的start()方法

第三种方式: 实现Callable接口

  1. 第一步编写一个类实现Callable接口,重写call()方法

  2. 启动线程

  3. 创建Callable接口实现类对象

  4. 创建一个FutureTask对象, 传递Callable接口实现类对象, FutureTask异步得到Callable执行结果, 提供get() FutureTask 实现Future接口( get()) 实现Runnable接口

  5. 创建一个Thread对象, 把FutureTask对象传递给Thread, 调用start()启动线程

多线程的简述_第5张图片


三种方式的区别:

**采用继承Thread类方式:**

(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。    

(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

采用实现Runnable接口方式: (推荐使用的方式)

(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。 可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

采用实现Callable接口:

(1)Callable规定的方法是call(),

(2)call方法可以抛出异常,run方法不可以

(3)Callable的任务执行后可返回值,而Runnable的任务是不能返回值

(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。


 线程的生命周期:

  1. 新建(通过构造) new

  2. 就绪(通过start()方法) Runnable

  3. 执行(通过资源调度,获取资源) Running

  4. 阻塞   Blocked

  5. 死亡  Dead

多线程的简述_第6张图片

NEW,新建:

  • 线程刚被创建,还没调用start方法,或者刚刚调用了start方法,调用start方法不一定"立即"改变线程状态,中间可能需要一些步骤才完成一个线程的启动。

可运行,RUNNABLE:

       start方法调用结束,线程由NEW变成RUNNABLE,线程存活着,并尝试抢占CPU资源,或者已经抢占到CPU资源正在运行,这俩种情况的状态都显示为RUNNABLE

锁阻塞,BLOCKED:

        线程A和线程B都要执行方法test,而且方法test被加了锁,线程A先拿 到了锁去执行test方法,线程B这时候需要等待线程A把锁释放。这时 候线程B就是处理BLOCKED。

无限期等待,WAINTING:

       一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入WAITING期,进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

有限期等待,TIMED_WAITING:

      和WAITING状态类似,但是有一个时间期限,时间到了,自己也会主动醒来

终止(死亡),TERMINATED:

      run方法执行结束的线程处于这种状态。

在图中可以看到,BLOCKED,WAITING,TIMED_WAITING这三种都属于线程阻塞,知识触发条件以及从阻塞状态恢复过来的条件不同。

线程在这三种情况的阻塞下,都具备:

  • 线程不执行代码

  • 线程不参与CPU时间片的争夺

一个线程所经历的基本情况简图:
多线程的简述_第7张图片
从就绪状态到运行状态,之间会经过多次反复的cPU执行权的争夺(线程调度)

你可能感兴趣的:(jvm,java,算法)