嗨~! 线程 —— 持续更新(^-^)V

进阶线程啦~.png

进程

是了解线程之前的首要概念,当我们想要在系统中运行程序,首先需要向操作系统申请资源(内存、文件句柄),申请资源在操作系统中的基本单位是进程。一个进程可以包含多个线程,同一个进程中的线程共享该进程中的资源,如内存空间、文件句柄等

HelloThread

线程创建、启动、运行
新建线程 new
启动线程 start
运行线程 run -- 运行一个线程就是让JVM执行该线程的 run 方法

  public class HelloThread {
    public static void main(String[] args) {
      Thread thread = new Thread();
      Thread childThread = new ChildThread();
      Thread childThred2 = new Thread(new ChildThread());
      Thread student = new Thread(new StudentRunnable());
      System.out.println("----------- Test thread's name in Called Method -----------");
      threadName();
      
      System.out.println("----------- Test 1. new Thread() 2.setName(\"HelloWorld\") -----------");
      thread.setName("HelloWorld");
      thread.start();
      System.out.println("Thread: " + thread.getName() + " starting");
      
      System.out.println("----------- Test ChildThread -----------");
      childThread.start();
      System.out.println("ChildThread: " + childThread.getName() + " starting...");
      childThred2.start();
      // 线程是“一次性用品”
      // 多次调用同一 thread 的 start 会出现 IllegalThreadStateException
      // 因为threadStatus != 0 0为线程初始状态
      // childThred2.start();
      System.out.println("ChildThread: " + childThred2.getName() + " starting...");
      System.out.println("----------- Test Student of Runnable -----------");
      student.start();
      System.out.println("StudentThread: " + student.getName() + " starting...");
    }
    
    public static void threadName() {
      System.out.println("The thread name of main called method's currentThread is " + Thread
        .currentThread().getName());
    }
    
  }

  class ChildThread extends Thread {
    @Override
    public void run() {
      // 执行run的顺序是不一定的
      // run执行完毕,线程即结束
      // 结束后,所占用的资源包括内存都将被JVM回收
      System.out.println(Thread.currentThread().getName() + " running...");
    }
  }

  class StudentRunnable implements Runnable {
    
    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + " running...");
    }
  }

Console Output:

  ----------- Test thread's name in Called Method -----------
  The thread name of main called method's currentThread is main
  ----------- Test 1. new Thread() 2.setName("HelloWorld") -----------
  Thread: HelloWorld starting
  ----------- Test ChildThread -----------
  ChildThread: Thread-1 starting...
  ChildThread: Thread-3 starting...
  ----------- Test Student of Runnable -----------
  ----------- Test run of ChildThread -----------
  Thread-3 running...
  ----------- Test run of ChildThread -----------
  Thread-1 running...
  Thread-4 running...
  StudentThread: Thread-4 starting...
  • Thread的创建默认下标从0开始,如源码示 threadInitNumber for 匿名线程自增长编号。threadInitNumber 初始为0
    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

创建线程综述:

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

基于Thread的run实现(实现Runnable的run),创建线程有两种方式:
1. 基于继承(Inheritance)。实现 Thread 中的 run 方法
2. 基于组合(Composition)。new Thread(Ruannable instance) 通过 Runnable 的实例,执行实例中的 run。实用组合更好的降低耦合

public class ThreadCreation {
  private static final String PREFIX = "prefix";
  
  public static void main(String[] args) {
    // ---------- 获取处理器个数 ----------
    final int processorNum = Runtime.getRuntime().availableProcessors();
    
    // ---------- 创建线程方式 ----------
    // ---------- 创建线程.Way1 基于继承 ----------
    ChildrenOfRunnable runnableTask = new ChildrenOfRunnable();
    IntStream.range(0, 2 * processorNum).mapToObj(index -> new Thread(runnableTask)).forEach(
      Thread::start);

    // ---------- 创建线程.Way2 基于组合 ----------
    Thread thread = new ChildrenOfThread();
    thread.start();
  }
    @Override
    public void run() {
      System.out.println("childrenOfThread is running.");
    }
  }
  
  static class ChildrenOfRunnable implements Runnable {
    private int index = 0;
    
    @Override
    public void run() {
  
  static class ChildrenOfThread extends Thread {
      System.out.println("childrenOfRunnable " + index++ + " is running.");
    }
  }
}

线程核心属性

  • id同一个JVM实例中不会存在重复的线程id,默认从0开始自增
  • name 主要便于开发人员查看,是可以重复的
  • daemon是否要设置为守护线程,默认同父线程daemon性质一致。守护线程一般执行一些重要性不是很高的任务,比如监听其他线程的运行情况
  • priority线程优先级,默认同父线程priority值一致,1≤n≤线程组priority≤10。优先级并一定保证线程会按照优先级的顺序执行,只是给到调度器一个提示信息。
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;

线程属性设置主要在Thread.init

    private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name.toCharArray();

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */
        g.checkAccess();

        /* Do we have the required permissions? */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

线程常用方法

  • synchronized void start() 启动线程。一个线程被start多次会抛出- IllegalThreadStateException异常
  • void run()实现线程的任务处理逻辑。一般,程序不应该直接调用该方法,由JVM调用
  • final synchronized void join()等待相应线程运行结束。T_A调用T_Bjoin()T_A将会等待T_B执行结束再执行
  • static void yield()主动放弃对当前时间片的占用,但是方法的执行并不可靠。若T_A调用yield方法:
    • 当前资源空闲,调度器会忽略这个提示,T_A继续执行
    • 当前资源忙,T_A主动放弃当前时间片,调度器收到提示切换上下文,T_A挂起
  • static void sleep() 一定会执行,挂起一定时间
  • static Thread currentThread()返回执行当前代码的线程
  • void interrupt()主动打断线程阻塞状态
  • boolean isInterrupted() 执行isInterrupted(false) 返回 if this thread has been interrupted; 即线程是否被打断过
  • static boolean interrupted() 实际上执行currentThread().isInterrupted(true); 即返回当前线程的interrupted并复位interrupted状态
  • native boolean isInterrupted(boolean ClearInterrupted)线程是否被打断,同时是否复位interrupted标识
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容