美文网首页
多线程编程

多线程编程

作者: NengLee | 来源:发表于2020-12-27 18:55 被阅读0次

    什么是进程?

    ​ 进程可以说是一个"执行中程序",是操作系统进行资源分配和调度的一个地独立单位,是应用程序运行的载体。

    什么是线程?

    ​ 线程(thread)是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。

    类比OOP思想,进程如果是火车,那么线程就是车厢

    区别

    1. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位,线程执行任务,进程不执行是载体
    2. 一个进程有一个或者多个线程组成,线程是一个进程中代码的不同执行路线
    3. 进程之间相互独立,但是同一个进程下个各个线程共享程序内存空间
    4. 调度和切换:线程上下文切换比进程上下文切换的要快

    多线程

    ​ 多线程是指在单位程序中可以同时运行多个不同线程,执行不同任务

    ​ 比单线程更具有优势:

    • 更高的运行效率
    • 多线程是模块化的编程模型
    • 与进程相比,线程的创建和切换开销更小

    并行和并发

    ​ Erlang 之父 Joe Armstrong 用一张5岁小孩都能看懂的图解释了并发与并行的区别

    并行与并发

    ​ 并行:同时执行任务。

    ​ 并发:交替运行任务。

    不能脱开时间线概念,例如一分钟并发量,一分钟的时间内有多少任务执行完毕。

    多线程创建方式

    1. 继承Thread,重写run方法

    2. 实现Runnable接口,重写run方法

    区别: Thread是对线程的程序,Runnable对任务/逻辑的抽象

    如何停止终止线程

    1. stop() 具有暴力销毁
        @Deprecated
        public final void stop() {
            stop(new ThreadDeath());
        }
    
        @Deprecated
        public final void stop(Throwable obj) {
            throw new UnsupportedOperationException();
        }
    
    
        public class ThreadDeath extends Error {
            private static final long serialVersionUID = -4417128565033088268L;
        }
    
    • 虽然打上@Deprecated,官方不建议用,非常危险不可控,随时在run某个执行点终止销毁,并且会在任务中持有的锁全部释放。即线程不安全!
    • 如何理解释放锁,假设在多线程编程中,A-Threadrun持有外部资源集合list加锁,同时B、C-Thread也在对list进行操作。突然对A-Thread进行了Stop,这么就间接对list锁的释放,于此同时导致B、C-Thread操作数据错乱。
    2. interrupt()、interrupted()、isinterrpted() 标志函数
    • interrupt方法:用于中断线程,标记设置为true,但是不会停止线程,在中断状态下如果线程处于阻塞状态(sleep/wait/join...),就会产生InterruptedException异常,并且线程处于阻塞,会立即中断标识立即清除为false
    • interrupted方法:测试当期线程是否处于中断状态,是返回true,并且调用后立即将中断标识清除false
    • isinterrpted方法:作用域该方法的线程对象所属的对应线程,(线程对象对应的线程不一定是当期运行的线程),调用后不会清除中断标记

    interrupt()... 源码

    /**
    *将线程的中断标记设置为true,但不会停止线程
    */
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();
    
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
    
    /**
     *静态获取,测试当前线程(当前线程是指运行interrupted()方法的线程)是否已经中断,且清除中断状态
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    
    /**
     *测试线程(调用该方法的线程)是否已经中断,不清除中断状态。
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    
    /**
     * privat - 设置
     */
    private native boolean isInterrupted(boolean ClearInterrupted);
    
    • sleep,wait,join等,就会中断抛InterruptException异常,就会清除中断标志位 isInterrupted()状态
    • 解决方案需要在catch中手动重置Thread.currentThread().interrupt();

    参考:

    @Test
    public void testMain() throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("=== testMain1 :" + myThread.getName() + "   " + myThread.isInterrupted());
        myThread.interrupt(); //中断线程,标识
        System.out.println("=== testMain2 :" + myThread.getName() + "   " + myThread.isInterrupted());
    }
    
    
    class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("继承Thread,重写run方法" + Thread.currentThread().getName());
            System.out.println(Thread.currentThread().getName() + " Top   interrupt is " + isInterrupted());
            while (true) {
                try {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " while  try  interrupt: " + isInterrupted());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().getName() + " while  catch  interrupt: " + isInterrupted());
                    Thread.currentThread().interrupt(); //手动修改处
                    System.out.println(Thread.currentThread().getName() + " while  catch  interrupt: " + isInterrupted() + "  (手动修改后)");
                }
                System.out.println("run End  while");
            }
    
        }
    }
    
    Logs输出

    线程的生命周期

    • 新建: new Thread
    • 就绪:等待时间轮转机制ing
    • 运行:run
    • 阻塞:cpu挂起当前线程
      • sleep (long millis)
      • wait (long timeout)
    • 死亡:任务完成即销毁
    线程的生命周期

    start()

    ​ 启动线程之后才有关联起来,不是new Thread()关联,这里只获取对象 Thread parent = currentThread();

    join()

    ​ 关联线程,串行可以调度 xxxThread等待就绪的线程,在此优先执行

    yield()

    ​ 让当前Thread交时间片,CPU重新(包括当期让出)交给其他Thread

    sleep(millis)

    ​ 当前Thread处于阻塞,挂起Time后在就绪,重新等待CPU时间轮转

    • interrupt() 标志中断线程作用

    wait()

    ​ Object对象的方法,如果没有设置时间,需要通过notify进行唤醒

    stop()

    ​ 暴力销毁线程,会释放资源锁,如在多线程会出现不可Error

    setDeamon()

    ​ 设置当前线程为守护线程,依赖其他线程,如进程中的所有线程执行完毕,守护线程也会跟着销毁,多用于辅助维护线程

    相关文章

      网友评论

          本文标题:多线程编程

          本文链接:https://www.haomeiwen.com/subject/fqzonktx.html