zoukankan      html  css  js  c++  java
  • 多线程基础篇

    一、进程与线程
    1. 概念:

      进程是操作系统结构的基础,是一个计算机中正在运行的程序实例,是分配给处理器并由处理器执行的一个实体,是由单一顺序执行显示、描述当前状态和一组相关系统资源组成的活动单元。如打开一个浏览器就是启动浏览器进程,打开word文档,就是启动word进程。

      线程是进程执行运算的最小单位,也就是执行调度的基本单元,一个进程中至少包含一个线程。

    2. 为什么会有多线程?

      多线程就像是流水线上的各部件加工,彼此独立工作,最后完成设备的生产。也就是说多线程的引用,可以将一个复杂的功能模块拆分成不同的任务来完成,这样也就大大提高了系统的性能,缩短了处理时间,提高了用户体验。


    二、线程运行的状态
    • 创建状态(new):新建一个线程对象,实现的方法有四种【继承Thread类、实现Runable接口、实现Callable接口、线程池Executors框架】

     

    • 就绪状态(Runable):线程对象被创建后,调用start()方法,进程进入可运行状态参与cpu时间片的竞争,等待被调度。

     

    • 运行状态(Running):线程对象获取cpu时间片,线程被执行。

     

    • 阻塞状态(Blocked):线程放弃cpu时间片,暂停执行。

       阻塞状态分为三种:

       1)等待阻塞:运行的线程调用o.wait()方法,该线程释放所有资源,进入“等待池”(也称为等待队列)中。进入这个状态后,线程不会自动唤醒,必须依赖其他线程调用o.notify()或o.notifyAll()方法,该线程才被唤醒,进入“锁池”中。

       2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用时,JVM会将该线程放入“锁池”中。

        3)其他阻塞:运行的线程调用Thread.sleep()或者t.join()方法,或者发出I/O请求时,JVM会将该线程置为阻塞状态,当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    • 死亡状态(Dead):线程正常执行完毕或抛出一个未处理的异常导致线程的提前结束,线程生命周期结束。

     

     


     三、sleep、yield、wait三者之间的区别

    1)sleep和yield是Thread下的静态方法。对运行的线程调用sleep()方法,线程让出cpu时间片,睡眠指定的时间,进入阻塞状态,该过程中,线程不会释放对象锁;到期后自动恢复,进入就绪状态,参与cpu时间片的竞争。对运行的线程调用yield()方法,线程让出cpu时间片,进入就绪状态,参与cpu时间片的竞争。

    2)wait和notify、notifyAll都是Object类下的方法。对运行的线程调用wait()方法,该线程释放所有资源,同时也会释放对象锁,进入“等待池”。线程不会自动唤醒,必须通过其他线程调用notify()或notifyAll()方法,线程才可被唤醒。(注意:由于notify()只是唤醒一个线程,但是由于不能确定具体唤醒的是哪一个线程,也许需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取对象的锁标记。

    3)【延伸】同wait()需要搭配notify()或notifyAll()成对出现一样,suspend()需要搭配resume()使用,区别在于wait()会释放对象的锁,而suspend()不会释放对象的锁。另外,suspend()方法和不指定超时期限的wait()方法的调用都可能产生死锁。


     四、线程中断 
    1 try {
    2                 Thread.sleep(100);
    3 //                wait();
    4 //                new Thread().join();
    5             } catch (InterruptedException e) {
    6                 e.printStackTrace();
    7             }

    先来看上面一段代码,当调用Thread类下的静态方法sleep,或者调用Thread类下的非静态方法,或者调用Object类下的wait方法,都需要捕获或者抛出中断异常 InterruptedException,那么什么情况下会出现这个异常呢,看看sleep的源码解释(wait和join等同一致):

     * @throws  InterruptedException
    * if any thread has interrupted the current thread. The
    * <i>interrupted status</i> of the current thread is
    * cleared when this exception is thrown.
    */
    public static native void sleep(long millis) throws InterruptedException;

    上面释义:当任何其他线程打断了当前线程,当前线程的中断状态被清除时,该异常就会抛出。很明显,释义已经解释很清楚了,什么是线程中断:
      当前线程被其他线程打断,且当前线程的中断状态被清除,那么这个线程就中断了
    那问题来了,什么方法可以去人工干预打断当前这个线程呢?

    线程Thread类下有个方法interrupt()来请求终止线程:
     1 /**
     2      * Interrupts this thread.
     3      *
     4      * <p> Unless the current thread is interrupting itself, which is
     5      * always permitted, the {@link #checkAccess() checkAccess} method
     6      * of this thread is invoked, which may cause a {@link
     7      * SecurityException} to be thrown.
     8      *
     9      * <p> If this thread is blocked in an invocation of the {@link
    10      * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
    11      * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
    12      * class, or of the {@link #join()}, {@link #join(long)}, {@link
    13      * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
    14      * methods of this class, then its interrupt status will be cleared and it
    15      * will receive an {@link InterruptedException}.
    16      *
    17      * <p> If this thread is blocked in an I/O operation upon an {@link
    18      * java.nio.channels.InterruptibleChannel InterruptibleChannel}
    19      * then the channel will be closed, the thread's interrupt
    20      * status will be set, and the thread will receive a {@link
    21      * java.nio.channels.ClosedByInterruptException}.
    22      *
    23      * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
    24      * then the thread's interrupt status will be set and it will return
    25      * immediately from the selection operation, possibly with a non-zero
    26      * value, just as if the selector's {@link
    27      * java.nio.channels.Selector#wakeup wakeup} method were invoked.
    28      *
    29      * <p> If none of the previous conditions hold then this thread's interrupt
    30      * status will be set. </p>
    31      *
    32      * <p> Interrupting a thread that is not alive need not have any effect.
    33      *
    34      * @throws  SecurityException
    35      *          if the current thread cannot modify this thread
    36      *
    37      * @revised 6.0
    38      * @spec JSR-51
    39      */
    40     public void interrupt() {
    41         if (this != Thread.currentThread())
    42             checkAccess();
    43 
    44         synchronized (blockerLock) {
    45             Interruptible b = blocker;
    46             if (b != null) {
    47                 interrupt0();           // Just to set the interrupt flag
    48                 b.interrupt(this);
    49                 return;
    50             }
    51         }
    52         interrupt0();
    53     }
    View Code

    另外Thread类下也提供了两个方法,静态方法interrupted()和非静态方法isInterrupted,但是这两种方法有些内在的差异:

    public boolean isInterrupted()                      

    isInterrupted是一个实例方法,主要用于判断当前线程对象的中断标志位是否被标记了,如果被标记了则返回true表示当前已经被中断,否则返回false,调用isInterrupted并不会清除线程对象的中断标识位

    public static boolean interrupted()

    interrupted是一个静态的方法,用于返回当前线程是否被中断,并且该方法调用结束的时候会清空中断标识位。


     五、守护线程

      守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程,这是它的作用——而其他的线程只有一种,那就是用户线程。所以java中的线程可以分两种:

    1、守护线程(典型的GC线程);2、用户线程

    守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行),此时,连jvm都停止运行了,守护线程当然也就停止执行了。

    在Java语言中,守护线程一般具有较低的优先级,它并非只由JVM内部提供,用户在编写程序时也可以自己设置守护线程,例如将一个用户线程设置为守护线程的方法就是在调用start()方法启动线程之前调用对象的setDaemon(true)方法。值得注意的是,当一个线程被设置成守护线程后,即使是finally的语句,也是不会执行的。

  • 相关阅读:
    MySQL-基本sql命令
    Java for LeetCode 203 Remove Linked List Elements
    Java for LeetCode 202 Happy Number
    Java for LeetCode 201 Bitwise AND of Numbers Range
    Java for LeetCode 200 Number of Islands
    Java for LeetCode 199 Binary Tree Right Side View
    Java for LeetCode 198 House Robber
    Java for LeetCode 191 Number of 1 Bits
    Java for LeetCode 190 Reverse Bits
    Java for LeetCode 189 Rotate Array
  • 原文地址:https://www.cnblogs.com/light-sunset/p/12840275.html
Copyright © 2011-2022 走看看