嗨~! 线程 —— 持续更新(^-^)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标识
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容