线程和 TA 的实例方法们

1. 线程与进程

1.1 进程

进程:操作系统所管理的基本运行单元被看作为进程
    进程是一个程序的执行;是系统进行资源分配和调度的独立单位;是操作系统结构的基础;是一个程序及其数据在物理机上顺序执行时所发生的活动。诶,还是说人话吧,在 windows 上打开任务管理器,如图1-1.操作系统进程管理图,查看进程项,诺,这个就是进程;

1.2 线程

线程:进程中独立运行的子任务看作为线程
    比如聊天程序这个进程,发送短信和下载文件就是两个独立运行的子任务。独立子任务可以同时进行,多个线程的优势也就体现出来了,最大限度利用CPU的空闲时间处理其他的任务。

在这里插入图片描述

图1-1.操作系统进程管理图

2. 线程的实例方法们

2.1 演示程序

import java.util.Arrays;
import java.util.Optional;

/**
 * @author niaonao
 * @className: ThreadInstanceMethod
 * @description: instance methods
 **/
public class ThreadInstanceMethod {
    public static void main(String[] args) throws InterruptedException {
        init();
    }

    private static void init() throws InterruptedException {
        final TargetRunnable targetRunnable = new TargetRunnable();
        Thread thread_01 = new Thread(targetRunnable);
        // 1> modify thread name, and return thread's id
        Optional.of(thread_01.getName()).ifPresent(System.out::println);
        thread_01.setName("Thread-01");
        Optional.of(thread_01.getName()).ifPresent(System.out::println);
        // 2> return this thread's ID.
        Optional.of(thread_01.getId()).ifPresent(System.out::println);
        // 3> run() and start()
        // thread could be start by start(),and cannot start by run()
        // Just Simply call an object instance method;
        // so the execution is in the main thread, not the line that calls the run() method
        thread_01.run();
        Optional.of(thread_01.getState()).ifPresent(System.out::println);
        thread_01.start();
        Optional.of(thread_01.getState()).ifPresent(System.out::println);

        // 4> throw new SecurityException if the current thread is not allowed to access this thread
        thread_01.checkAccess();
        // 5> get ClassLoader and set ClassLoader
        ClassLoader classLoader = thread_01.getContextClassLoader();
        Optional.of(classLoader.getClass().getName()).ifPresent(System.out::println);
        thread_01.setContextClassLoader(classLoader);
        // 6> get thread's priority and set priority
        // public final static int MIN_PRIORITY = 1;
        // public final static int NORM_PRIORITY = 5;
        // public final static int MAX_PRIORITY = 10;
        Optional.of(thread_01.getPriority()).ifPresent(System.out::println);
        thread_01.setPriority(Thread.MIN_PRIORITY);
        // 7> Returns an array of stack trace elements representing the stack dump of this thread.
        StackTraceElement[] stackTraceElementArray = thread_01.getStackTrace();
        Arrays.stream(stackTraceElementArray).forEach(System.out::println);
        // 8> belong to threadGroup
        ThreadGroup threadGroup = thread_01.getThreadGroup();
        System.out.println(threadGroup);
        // 9>  return handler for uncaught exception
        Thread.UncaughtExceptionHandler handler = thread_01.getUncaughtExceptionHandler();
        System.out.println(handler);
        // 10> set a handler for uncaught exception
        thread_01.setUncaughtExceptionHandler(null);

        // 11> interrupt current thread, and Thread.State to be TERMINATED
        thread_01.interrupt();
        // 12> check thread has been interrupted
        boolean isInterrupt = thread_01.isInterrupted();
        System.out.println(isInterrupt);
        // 13> get Thread.State; NEW/RUNNABLE/BLOCKED/WAITING/TIMED_WAITING/TERMINATED
        Thread.State state = thread_01.getState();
        Optional.of(state).ifPresent(System.out::println);
        // 14> check thread isAlive
        boolean isAlive = thread_01.isAlive();
        System.out.println(isAlive);
        // 15> Waits for this thread to die, then continue to next step
        Thread thread_02 = new Thread(targetRunnable, "Thread-02");
        thread_02.start();
        System.out.println(thread_02.toString()+"Thread-02 RUNNABLE and alive...");
        thread_02.join();
        System.out.println(thread_02.toString()+"Thread-02 TERMINATED and die...");

        // 16> daemon thread
        Thread thread_03 = new Thread(targetRunnable, "Thread-03");
        thread_03.setDaemon(true);
        // 17 whether this thread is daemon thread
        boolean isDaemon = thread_01.isDaemon();
        System.out.println(isDaemon);
    }
}

class TargetRunnable implements Runnable {

    @Override
    public void run() {
        Optional.of(Thread.currentThread()).ifPresent(System.out::println);
    }
}

2.2 补充说明

2.2.1 setName and getName, getId

    线程名称,默认名称为 Thread-index,index 属于[0, +∞)。线程名称支持自定义,允许重复,不可为空;线程 ID 自增唯一。

2.2.2 run() and start()

    通过 start() 方法启动一个线程实例,交由 JVM 处理,run() 的内部逻辑是线程启动后会调用该方法执行内部逻辑。线程一般需要重写 run() 方法,来自定义业务逻辑。
    调用 start() 方法也不是立即启动线程,线程首先是变更为 RUNNABLE 状态,可执行状态下抢到 CPU 资源才会真正的执行,所以一组线程对象调用 start() 的先后顺序也不代表一组线程真正的启动顺序。
    一个线程对象实例直接通过调用 run() 方法,与普通实例对象调用普通方法无异,和线程无关,不会改变线程的状态;
    一个线程对象实例只能调用一次 start() 方法,再次调用会抛出异常 IllegalThreadStateException;start() 方法会启动线程,将线程状态由 NEW 变更为 RUNNABLE,只有 NEW 状态的线程实例可以调用 start() 方法来启动线程。

在这里插入图片描述

图2-1.线程方法 run() 与 start() 对照图
2.2.3 checkAccess()

    校验当前线程是否能够修改该线程;若不允许修改线程则会抛出异常 SecurityException

2.2.4 getContextClassLoader() and setContextClassLoader(ClassLoader cl)

    获取线程上下文类加载器,同样的支持设置上下文类加载器;
    举个应用场景:服务提供者接口(Service Provider Interface,SPI),SPI 的接口由 Java 的核心库来提供,由引导类加载器来加载,SPI 的实现类一般由系统类加载器来加载。引导类加载器无法找到部分 SPI 的实现类,此时通过线程上下文类加载器就可以设置对应的类加载器来满足场景。

2.2.5 getPriority() and setPriority(int newPriority)

优先级高(大)的线程得到的 CPU 资源更多,CPU 优先执行优先级高的任务

public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;

    设置线程优先级,一般的默认优先级为 NORM_PRIORITY
    优先级具有继承性,由 A 线程来启动 B 线程,则 B 线程的优先级会继承 A 线程的优先级;
    优先级具有随机性,优先级高的任务会被优先执行,并不是优先级低的就一定要后执行,只是优先级低的任务执行频率低,也存在优先级低的任务先完成执行,优先级高的任务还未完成执行的情况
    优先级具有规则性,优先级高的任务优先执行

2.2.6 getStackTrace()

    返回堆栈转储的堆栈跟踪信息

2.2.7 getThreadGroup()

    所属线程组

2.2.8 getUncaughtExceptionHandler() and setUncaughtExceptionHandler()

    获取(设置)线程执行中未捕获异常的处理器

2.2.9 interrupt() and isInterrupted()

    interrupt() 中断线程,更新线程状态为 TERMINATED。
    isInterrupted() 校验线程是否被中断

2.2.10 getState()

    获取线程状态,Thread.State 包含以下状态 NEW/RUNNABLE/BLOCKED/WAITING/TIMED_WAITING/TERMINATED

2.2.11 isAlive()

    校验是否为活动线程。活动线程:started and not yet died

2.2.12 isDaemon()

    校验是否为守护线程。线程分为两类:用户线程和守护线程;当进程中不存在用户线程时,守护线程自动销毁;守护线程是一种为用户线程提供便利服务的特殊线程,典型的守护线程就是垃圾回收线程(GC)

演示程序:

import java.util.Optional;

/**
 * @className: ThreadInstanceDaemon
 * @description: daemon thread
 * @author: niaonao
 **/
public class ThreadInstanceDaemon {
    public static void main(String[] args) throws InterruptedException {
        init();
    }

    private static void init() throws InterruptedException {
        Thread mainThread = Thread.currentThread();
        System.out.println(mainThread.toString() + " is executing...");
        Thread daemonThread = new Thread(new DaemonRunnable(), "Thread-Daemon-01");
        daemonThread.setDaemon(true);
        daemonThread.start();
        mainThread.sleep(5_000L);
        System.out.println(mainThread.toString() + " Will be executed...");
    }
}

class DaemonRunnable implements Runnable {
    @Override
    public void run() {
        while (true) {
            Optional.of(Thread.currentThread()).ifPresent(System.out::println);
            try {
                Thread.sleep(1_000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果

Thread[main,5,main] is executing...
Thread[Thread-Daemon-01,5,main]
Thread[Thread-Daemon-01,5,main]
Thread[Thread-Daemon-01,5,main]
Thread[Thread-Daemon-01,5,main]
Thread[Thread-Daemon-01,5,main]
Thread[main,5,main] Will be executed...

    从执行结果来看,守护线程 daemonThread 在主线程执行结束就自动销毁了

2.2.13 join()

    等待当前线程执行结束或中断;
演示程序

/**
 * @className: ThreadInstanceJoin
 * @description: join(), and wait this thread to die
 * @author: niaonao
 **/
public class ThreadInstanceJoin {
    public static void main(String[] args) throws InterruptedException {
        final Thread mainThread = Thread.currentThread();
        final JoinRunnable joinRunnable = new JoinRunnable();
        System.out.println(mainThread.toString() + ", and execute start...");
        togetherExecute(joinRunnable);
        oneByOneExecute(joinRunnable);
        System.out.println(mainThread.toString() + ", then execute end...");
    }

    private static void togetherExecute(Runnable joinRunnable) throws InterruptedException {
        Thread joinThread_01 = new Thread(joinRunnable, "Thread-01");
        Thread joinThread_02 = new Thread(joinRunnable, "Thread-02");
        Thread joinThread_03 = new Thread(joinRunnable, "Thread-03");
        joinThread_01.start();
        joinThread_02.start();
        System.out.println("joinThread_01/02.start() and execute start...");
        joinThread_01.join();
        joinThread_02.join();
        System.out.println("joinThread_01/02.start() and execute end...");
        joinThread_03.start();
    }

    private static void oneByOneExecute(Runnable joinRunnable) throws InterruptedException {
        Thread joinThread_05 = new Thread(joinRunnable, "Thread-05");
        Thread joinThread_04 = new Thread(joinRunnable, "Thread-04");

        joinThread_04.start();
        System.out.println(joinThread_04.toString() + ": start() and execute start...");
        joinThread_04.join();
        System.out.println(joinThread_04.toString() + ": start() and execute end...");

        joinThread_05.start();
        System.out.println(joinThread_05.toString() + ": start() and execute start...");
        joinThread_05.join();
        System.out.println(joinThread_05.toString() + ": start() and execute end...");
    }
}

class JoinRunnable implements Runnable {
    @Override
    public void run() {
        Thread currentThread = Thread.currentThread();
        System.out.println(currentThread.toString() + ": run() and execute start...");
        // 模拟耗时操作
        String name = currentThread.getName().substring(6, 9);
        for (int i = 0; i < 50; i++) {
            System.out.print(name);
        }
        System.out.println("\n" + currentThread.toString() + ": run() then execute end...");
    }
}

运行结果

Thread[main,5,main], and execute start...
joinThread_01/02.start() and execute start...
Thread[Thread-01,5,main]: run() and execute start...
Thread[Thread-02,5,main]: run() and execute start...
-02-02-02-02-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-01-02-02-02-02-02-02-02-02-02-02-02
Thread[Thread-01,5,main]: run() then execute end...
-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02-02
Thread[Thread-02,5,main]: run() then execute end...
joinThread_01/02.start() and execute end...
Thread[Thread-04,5,main]: start() and execute start...
Thread[Thread-03,5,main]: run() and execute start...
-03-03-03-03-03-03-03-03Thread[Thread-04,5,main]: run() and execute start...
-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-04-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-03-04-04-04-04-04-04-04-03-03-03-04-04-04-03-03-03-03-03-03-03-04-04-04-04-04-03-03-03-03-03-03-03-03-03-03-03-04
Thread[Thread-04,5,main]: run() then execute end...

Thread[Thread-03,5,main]: run() then execute end...
Thread[Thread-04,5,]: start() and execute end...
Thread[Thread-05,5,main]: start() and execute start...
Thread[Thread-05,5,main]: run() and execute start...
-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05-05
Thread[Thread-05,5,main]: run() then execute end...
Thread[Thread-05,5,]: start() and execute end...
Thread[main,5,main], then execute end...

    从运行结果来看,使用 join() 方法的线程,会执行结束后才会继续执行主线程的逻辑;没有使用 join() 的情况下,多线程是异步执行的,没有顺序执行。

2.2.14 已过时的方法

    不再详细说明,简述以下方法的功能,感兴趣可以看源码中方法实现逻辑

// 已过时的方法;计算线程的栈帧数,线程会被销毁。
countStackFrames();
// 已过时的方法;销毁线程,存在造成死锁的风险;
// 如果目标线程拥有的锁保护关键系统资源,当它被破坏,没有线程都不能再次访问该资源。 如果另一个线程曾试图锁定该资源,则会出现死锁
destory();
// 已过时的方法;Resumes a suspended thread. 恢复挂起的线程
resume();
// 已过时的方法,停止执行中的线程
stop()
// 已过时的方法,暂停执行并挂起线程
suspend()

suspend() 和 resume() 会造成独占并锁死资源,也可能造成数据不同步问题。stop() 等作废方法都存在产生不可预料的结果,所以不推荐使用。

附:官方文档

在线文档:https://docs.oracle.com/javase/8/docs/api/
离线文档:https://www.oracle.com/java/technologies/javase-jdk8-doc-downloads.html

Powered By niaonao

©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页