001-多线程基础-进程线程、线程状态、优先级、用户线程和守护线程

一、进程与线程

1、DOS系统【单进程系统】

  最早的时候DOS有一个特点:只要电脑有病毒,那么电脑就死机了。
  原因:传统的DOS系统属于单进程系统,即:在同一时间段内只允许有一个程序运行。

2、Windows系统【多进程多线程】

  电脑中毒也可以运行,但是会变慢
  原因:因为在一个cpu、一块资源的情况下,程序利用一些轮转算法,可以让一个资源在一个时间段可以同时处理多个程序(进程),但是在一个时间点上只允许一个进程去执行。
  windows:任务管理器
  linux:ps
  在每一个进程上可以划分出若干个线程,那么线程的操作一定是要比进程更快。多线程操作要超多进程操作。但是所有的线程都一定是要在进程的基础上进行划分。
  所以进程一旦消失,那么线程一定消失
  线程依附于进程存在。

  进程:一个进程就是一个“执行中的程序”,是程序在计算机上的一次运行活动。程序要运行,系统就在内存中为该程序分配一块独立的内存空间,载入程序代码和资源进行执行。程序运行期间该内存空间不能被其他进程直接访问。系统以进程为基本单位进行系统资源的调度和分配。

  线程:程序的执行具体是通过线程来完成的,所以一个进程中至少有一个线程。回忆一下 HelloWrold 程序中main方法的执行,其实这时候,Java虚拟机会开启一个名为“main”的线程来执行程序代码。一个进程可以包含多个线程,这些线程共享数据空间和资源,但又分别拥有各自的执行堆栈和程序计数器。线程是CPU调度的基本单位。

二、java的线程介绍【线程状态、优先级、用户线程和守护线程】

1、java线程的生命周期【线程状态】

  java线程在他的生命周期内有几种不同的状态:线程初始化,启动,运行和死亡。

  

上图所示的状态解释如下:【可通过thread dump查看】

  ● new 是指线程被初始化,但是还没有调用其start方法,还没有开始执行

    每一个线程,在堆内存中都有一个对应的Thread对象。Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态。在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象。

  ● runnable 调用线程的start方法之后,线程开始执行其任务,这时候线程是运行状态

    该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行。 这个状态的线程比较正常,但如果线程长时间停留在在这个状态就不正常了,这说明线程运行的时间很长(存在性能问题),或者是线程一直得不得执行的机会(存在线程饥饿的问题)。

  ● waiting 有时候线程需要等待另外一个线程执行完毕之后再执行,这时候线程处于等待状态,处于等待状态的线程需要其他线程notify之后才能恢复到运行状态

    处在该线程的状态,正在等待某个事件的发生,只有特定的条件满足,才能获得执行机会。而产生这个特定的事件,通常都是另一个线程。也就是说,如果不发生特定的事件,那么处在该状态的线程一直等待,不能获取执行的机会。比如说,A线程调用了obj对象的obj.wait()方法,如果没有线程调用obj.notify或obj.notifyAll,那么A线程就没有办法恢复运行;如果A线程调用了LockSupport.park(),没有别的线程调用LockSupport.unpark(A),那么A没有办法恢复运行。

  ● timed waiting 运行中的线程可以进入到定时等待的状态,这时候线程间隔指定的时间间隔之后就会恢复到运行状态

    J.U.C中很多与线程相关类,都提供了限时版本和不限时版本的API。TIMED_WAITING意味着线程调用了限时版本的API,正在等待时间流逝;当等待时间过去后,线程一样可以恢复运行。如果线程进入了WAITING状态,一定要特定的事件发生才能恢复运行;而处在TIMED_WAITING的线程,如果特定的事件发生或者是时间流逝完毕,都会恢复运行。

  ● terminated 当线程任务执行完毕或者被abort的时候线程处于终止状态

    线程执行完毕,执行完run方法正常返回,或者抛出了运行时异常而结束,线程都会停留在这个状态。这个时候线程只剩下Thread对象了,没有什么用了。

  线程的状态在Thread.State这个枚举类型中定义:

    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

2、java线程的优先级  

  每一个java线程都有一个优先级,操作系统可以通过线程的优先级决定决定将cpu分配给哪个线程。优先级越高的线程越可能得到cpu资源。
  java线程优先级的值在1-10之间,1是常量MIN_PRIORITY,10是常量MAX_PRIORITY 。默认情况下java的线程的优先级是NORM_PRIORITY 即5.
  高优先级的线程通常更重要,更有可能获得cpu时间资源,但是并不能保证绝对可以获得cpu。

3、用户线程和守护线程

  java中线程分为两种类型:用户线程和守护线程。通过Thread.setDaemon(false)设置为用户线程;通过Thread.setDaemon(true)设置为守护线程。如果不设置此属性,默认为用户线程
  用户线程和守护线程的区别:【用户线程存活程序存活,其他则结束
    1. 主线程结束后用户线程还会继续运行,JVM存活;主线程结束后守护线程和JVM的状态又下面第2条确定。
    2.如果没有用户线程,都是守护线程,那么JVM结束(随之而来的是所有的一切烟消云散,包括所有的守护线程)。

  main方法说明

  1.Main线程是个非守护线程,不能设置成守护线程。
    main线程是由java虚拟机在启动的时候创建的,进入程序的入口。main方法开始执行的时候,main用户线程已经创建好并在运行了。对于运行中的线程,不可以调用Thread.setDaemon(),调用会抛出异常Exception in thread "main"
  2.Main线程结束,如果还有其他用户线程则继续运行,如果都是守护线程则直接结束
    主线程,只是个普通的非守护线程,用来启动应用程序,不能设置成守护线程;除此之外,它跟其他非守护线程没有什么不同。主线程执行结束,其他用户线程一样可以正常执行。
    按照操作系统的理论,进程是资源分配的基本单位,线程是CPU调度的基本单位。对于CPU来说,其实并不存在java的主线程和子线程之分,都只是个普通的线程。进程的资源是线程共享的,只要进程还在,线程就可以正常执行,换句话说线程是强依赖于进程的。也就是说,线程其实并不存在互相依赖的关系,一个线程的死亡从理论上来说,不会对其他线程有什么影响。
    java虚拟机(相当于进程)退出的时机是:虚拟机中所有存活的线程都是守护线程。只要还有存活的非守护线程虚拟机就不会退出,而是等待非守护线程执行完毕;反之,如果虚拟机中的线程都是守护线程,那么不管这些线程的死活java虚拟机都会退出。

  补充说明:

    定义:守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开。
    优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。
    设置:通过setDaemon(true)来设置线程为“守护线程”;将一个用户线程设置为守护线程的方式是在线程启动用线程对象的setDaemon方法。
    示例: 垃圾回收线程就是一个经典的守护线程,当我们的程序中不再有任何运行的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是JVM上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。
    生命周期:守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。那Java的守护线程是什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出

    例子程序:

      thread = new Thread(this);
      thread.setDaemon(true);
      thread.start();
     当java虚拟机中没有非守护线程在运行的时候,java虚拟机会关闭。当所有常规线程运行完毕以后,守护线程不管运行到哪里,虚拟机都会退出运行。所以你的守护线程最好不要写一些会影响程序的业务逻辑。否则无法预料程序到底 会出现什么问题。

示例:

    public static void main(String[] args) throws Exception {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                String daemon = Thread.currentThread().isDaemon() ? "daemon" : "not daemon";
                while (true) {
                    System.out.println("Im is running " + daemon + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        };
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        thread.start();
        Thread.sleep(3000);
        System.out.println("main is over");
    }

  运行上面程序,输出如下内容后程序就退出了。
    Im is running daemon14:14:48
    Im is running daemon14:14:49
    Im is running daemon14:14:50
    main is over

  可以看到在主线程退出之后,deamon线程也就被终止了,同时程序也就退出了。
  我们对上面程序稍作改动,将t.setDaemon(true)注释掉,再看下运行结果。
    Im is running not daemon14:15:29
    Im is running not daemon14:15:30
    Im is running not daemon14:15:31
    main is over
    Im is running not daemon14:15:32
    Im is running not daemon14:15:33

    ……

  可以看到在主线程退出之后,t线程还在继续执行,这是因为线程t默认情况下是非守护线程,尽管主线程退出了,他还是在继续执行着。
  需要注意设置线程是否为守护线程必须在其执行之前进行设置,否则会抛出异常IllegalThreadStateException。这一点可以从Thread类的setDaemon(boolean)的源码中得到求证。如下源码:

    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

  可以看到如果线程在live状态调用setDaemon会抛出异常。

3、java多线程实现的两种方式

  1. 使用Runnable接口实现多线程

    使用Runnable接口实现多线程需要两个步骤,首先实现Runnable接口类,然后声明Thread实例,调用thread实例的start方法,开始执行。

  2. 从Thread类继承实现java的多线程

    从java的Thread类继承实现多线程,也是实现其run方法,然后声明实例,并调用实例的start方法启动线程。

4、java Thread类的主要方法介绍

Thread的实例方法:


方法定义


方法说明


public void start()


最常用的方法,顾名思义启动线程,即开始执行线程的run方法


public void run()


如果线程重写了run方法,那么执行重写的方法,否则执行线程的Runnable接口中定义的run方法


public final void setName(String)


设置线程的名称


public final void setPriority(int)


设置线程的优先级(范围在1-10包含1,10)


public final void setDeamon(boolean)


设置线程是否是后台线程


public final void join(long)


在另外一个线程中调用当前线程的join方法,会导致当前线程阻塞,直到另一线程执行完毕,或者超过参数指定毫秒数


public void interrupt()


中断线程


public final boolean isAlive()


线程是否处于存活状态,线程在启动和结束之前都处于存活状态

Thread类的常用静态方法:


方法定义


方法说明


public static void yield()


使当前运行线程相同优先级的线程获得执行机会,类似sleep,但是只会将cpu让给相同优先级的线程


public static void sleep(long)


使当前线程休眠指定毫秒的时间


public static boolean holdsLock(Object x)


判断当前线程是否拥有对象的锁


public static Thread currentThread()


获得当前线程实例


public static void dumpStack()


打印当前线程的执行堆栈,这对多线程程序的调试很有帮助

时间: 2024-10-12 21:18:21

001-多线程基础-进程线程、线程状态、优先级、用户线程和守护线程的相关文章

细说进程五种状态的生老病死——双胞胎兄弟Java线程

java线程的五种状态其实要真正高清,只需要明白计算机操作系统中进程的知识,原理都是相同的. 系统根据PCB结构中的状态值控制进程. 单CPU系统中,任一时刻处于执行状态的进程只有一个. 进程的五种状态:初始态,执行态,等待态,就绪态,终止态. 执行状态:一个进程获得了必要资源,并且在CPU上执行时的状态. 执行态进程因为等待某种事件的发生处于等待状态. 执行态进程的时间片用完或在抢占式调度中有更高优先级的进程时变为就绪状态. 阻塞原语:一个执行进程期待某一个事件的发生,但发生条件尚不具备,该进

Python36 1.joinablequeue 2.线程理论 3.多线程对比多进程 4.线程的使用方式 4.1.产生 线程的两种方式 4.2.守护线程 4.3.线程安全问题 4.3.1.互斥锁 4.3.2.死锁 4.3.3.可重入锁 4.3.4.信号量

复习1.守护进程2.互斥锁(解决数据错乱的方法)3.IPC(进程间通讯)4.生产者与消费者模型 详解:1.守护进程 一个进程可以设为另一个进程的守护进程 特点:被守护的进程结束时,守护进程也会随之结束 本质:父进程交给子进程一个任务,然而父进程 先于子进程结束了,子进程的任务也就没有必要 继续执行了 格式:开始前加 p.daemon=True 2.互斥锁(解决数据错乱的方法)方法一:互斥锁 互斥 互相排斥 锁的本质:一个标志 标志的两个状态: 1.锁定 2.未锁定 什么时候用? 当多个进程要操作

Java多线程系列--“基础篇”10之 线程优先级和守护线程

概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3479982.html 1. 线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5.“高优先级线程”会优先于“低优先级线程”执行. java 中有两种线程:用户线程和守护线程.可以通过isDaemon()方法来区别它们:如果返回false,则说明该线程

再谈多线程编程(一)——线程的概念、多线程的创建、守护线程、线程状态的转化

1.什么是线程以及多线程与进程的区别 在现代操作在运行一个程序时,会为其创建一个进程.例如启动一个QQ程序,操作系统就会为其创建一个进程.而操作系统中调度的最小单位元是线程,也叫轻量级进程,在一个进程里可以创建多个线程,这些线程都拥有各自的计数器,堆栈和局部变量等属性,并且能够访问共享的内存变量.处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行.因此我们可以这样理解: 进程:正在运行的程序,是系统进行资源分配和调用的独立单位.每一个进程都有它自己的内存空间和系统资源. 线程:是进程中

线程的生命周期和线程的状态转换图

一.线程的生命周期 1.线程的5种状态:新建(New),就绪(Runnable),运行(Running),阻塞(Blocked),死亡(Dead) 2.线程的生命周期图解:(参考传智播客刘意2015Java基础视频讲义) 二.线程的状态转换图 1.线程的5种状态:新建(New),就绪(Runnable),运行(Running),阻塞(Blocked),死亡(Dead) 线程变化的状态转换图例如以下: 1)新建状态(New):新创建了一个线程对象. 2)就绪状态(Runnable):线程对象创建后

【python】-- 继承式多线程、守护线程

继承式多线程 1.定义 继承式多线程是自己自定义类,去继承theading.Tread这个类,通过类实例.start()启动,去执行run方法中的代码. import threading import time class MyThread(threading.Thread): # 继承threading.Thread """继承式多线程""" def __init__(self, n): threading.Thread.__init__(se

关于守护进程和守护线程的区别

一.守护进程 1.1.什么是守护进程? 1.守护进程会在主进程代码运行结束的情况下,立即挂掉. 2.守护进程本身就是一个子进程. 3.主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, 1.2.为什么要用守护进程? 1.守护进程本身就是一个子进程,所以在主进程需要将任务并发执行的时候需要开启子进程. 2.当该子进程执行的任务生命周期伴随着主进程的生命周期时,就需要将该子进程做成守护进程.

守护线程、守护进程

1. 几点认识: java中有两类线程:user thread(用户线程),daemon thread(守护线程) 守护线程为其他线程的运行提供服务,例如GC线程(垃圾回收线程),内存管理线程. 虚拟机判断程序执行结束的标准时不考虑守护线程:如果user thread全部撤离,daemon thread因为无服务对象,所以虚拟机也就退出了. public final void setDaemon(boolean on) :用户自行设定守护线程 是JVM模拟了操作系统中的“守护进程”而定义出的一种

Java 多线程(四)之守护线程(Daemon)

定义 Java 中有两种线程: 一种是用户线程(User Thread),一种是守护线程(Daemon Thread). 守护线程是一种特殊的线程, 它的特殊有"陪伴"的含义, 当线程中不存在非守护线程时, 则守护线程自动销毁. 垃圾回收线程就是一种守护线程, 当线程中没有非守护线程了, 则垃圾回收线程就会自动销毁. 因此, 守护线程的作用就是为其他非守护线程的线程服务, 当非守护线程不存在时, 其自然就没有存在的必要了. 如何创建 创建过程与一般的线程一样, 只需要在创建完之后调用如