0
点赞
收藏
分享

微信扫一扫

使用冒泡排序模拟实现qsort函数

杏花疏影1 04-15 16:30 阅读 2
java-eejava

目录


Thread

Thread 就是在 Java 中,线程的代言人。系统中的一个线程,就对应到 Java 中的一个 Thread 对象。围绕线程的各种操作,都是通过 Thread 来展开的

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联

用我们上面的例子来看,每个执行流,也需要有一个对象来描述,类似下图所示,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

在这里插入图片描述

Thread类的常用构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, Strin name)使用 Runnable 对象创建线程对象,并命名
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");```

Thread类的常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  1. ID(getId):线程的身份表示(在JVM这里给线程设定的身份标识),一个线程可以有多个身份标识

  2. 名称(getName):各种调试工具用到

  3. 状态(getState):Java中的线程状态和操作系统中有一定差异

  4. 优先级(getPriority):设置/获取线程优先级作用不是很大,线程的调度主要还是系统内核来负责的,系统调度的速度实在太快

  5. 是否后台线程(isDaemon)

    • 后台线程/守护线程:不太影响进程结束

    • 前台线程:会影响进程结束,如果前台线程没执行完,进程是不会结束的

    • 一个进程中所有的前台线程都执行完,退出了,此时即使存在后台线程仍然没执行完也会随着进程一起退出

    • 影响进程退出的就是前台,不影响的就是后台

    • 创建的线程默认是前台线程,通过setDaemon显式的设置成后台

  6. 是否存活(isAlive):Thread对象,对应的线程(系统内核中)是否存活。

    • Thread对象的生命周期,并不是和系统中的线程完全一致的
  7. 是否被中断(isInterrupted):看下面

启动一个线程-start()

  1. start方法,在系统中真正创建出线程
    1. 创建出PCB
    2. 把PCB加入到对应链表
  2. 操作系统内核=内核+配套的程序
  3. 内核:一个系统最核心的功能
    1. 对下,管理好各种硬件设备
    2. 对上,给各种程序提供稳定的运行环境
  4. start方法本身执行成功是一瞬间的,只是告诉系统你要创建一个线程,调用完start后,代码就会立即继续执行start后续的逻辑

终止一个线程

  1. 一个线程的run方法执行完毕,就算终止了

  2. 此处的终止线程,就是想办法让run方法能够尽快执行完毕

  3. 方法:

    1. 程序员手动设定标志位,通过这个来让run尽快结束
    private static class MyRunnable implements Runnable {
        public volatile boolean isQuit = false;
    
        @Override
        public void run() {
            while (!isQuit) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        target.isQuit = true;
    }
    
    1. 直接Thread类,给我们提供好了现成的标志位,不用手动设置标志位
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 两种方法均可以
            while (!Thread.interrupted()) {
                //while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().getName()
                            + ": 有内鬼,终止交易!");
                    // 注意此处的 break
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        thread.interrupt();
    }
    
  4. 当sleep被唤醒以后,程序员可以有以下几种操作方式:

    1. 立即停止循环,立即结束线程(直接break)
    2. 继续做点别的事情,过一会儿再结束线程(catch中执行别的逻辑,执行完再break)
    3. 忽略终止的请求,继续循环(不写break)
  5. thread 收到通知的方式有两种:

    1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志
      • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程
    2. 否则,只是内部的一个中断标志被设置,thread 可以通过
      • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
      • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

等待一个线程-join()

  1. 多个线程是并发执行的。具体的执行过程都是由操作系统负责调度的。操作系统的调度线程的过程,是“随机”的。无法确定线程执行的先后顺序
  2. 等待线程,就是一种规划 线程结束 顺序的手段
  3. 注意:join()方法也会抛出Interrupted异常
  4. 谁调用join方法,谁就强占cpu资源,直至执行结束
  5. A B两个线程,希望B先结束A后结束,此时就可以让A线程中调用B.join()的方法。此时,B线程还没执行完,A线程就会进入"阻塞"状态。就相当于给B留下了执行的时间。B执行完毕之后,A再从阻塞状态中恢复回来,并且继续往后执行。如果A执行到B.join()的时候,B已经执行完了,A就不必阻塞了,直接往下执行就可以了
  6. 阻塞:让代码暂时不继续执行了(该线程暂时不去CPU上参与调度)
  7. sleep也能让线程阻塞,阻塞是有时间限制的
  8. join的阻塞,则是“死等”“不见不散”
  9. sleep、join、wait…产生阻塞之后,都是可能被interrupt方法唤醒的,这几个方法都会在被唤醒之后自动清除标志位(和sleep类似),这些方法都会抛出Interrupted异常

线程的状态

  • 先谈谈进程里PCB里的状态字段:就绪阻塞状态(这些是系统设定的状态,Java又把这些细分了)
  • 以下则是线程的状态:
  1. NEW**(开始前)**: 安排了工作, 还未开始行动 (Thread对象创建好了,但还没有调用start()方法)

  2. RUNNABLE**(就绪状态): 可工作的. 又可以分成正在工作中即将开始工作**

    1. 线程正在CPU上运行

    2. 线程正在排队,随时可以去CPU运行

  3. BLOCKED**(阻塞状态)**: 这几个都表示排队等着其他事情 :因为锁

  4. WAITING**(阻塞状态)**: 这几个都表示排队等着其他事情 :因为调用了wait

  5. TIMED_WAITING**(阻塞状态)**: 这几个都表示排队等着其他事情 :因为调用了sleep

  6. TERMINATED**(结束后)**: 工作完成了

  • 线程状态转换图

在这里插入图片描述

举报

相关推荐

0 条评论