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的语句,也是不会执行的。

  • 相关阅读:
    在Unix上使用管道压缩exp导出文件
    自制CPU的黑暗历程一
    Error C1189: #error: Please use the /MD switch for _AFXDLL builds
    Redis乐观锁解决高并发抢红包的问题
    PHP分页类
    汇编基础——使用nasm和bochs学习汇编
    数据同步工具DBsync
    完成端口的一些教程
    sdf
    (转)C#(WIN FORM)两个窗体间LISTVIEW值的修改
  • 原文地址:https://www.cnblogs.com/light-sunset/p/12840275.html
Copyright © 2011-2022 走看看