关于java:JAVA中的线程世界

过程与线程

  • 过程是程序向操作系统申请资源(如内存空间和文件句柄)的根本单位.
  • 线程是过程中可独立执行的最小单位.

JAVA线程API

  1. 在Java中创立一个线程就是创立一个Thread类的实例。
  2. 每个线程都有其要执行的工作.线程工作的解决逻辑是在Thread类的run办法中实现或进行调用的,因而run办法相当于线程工作逻辑解决的入口办法,它由java虚拟机在运行相应的线程时进行调用,而不是由利用代码进行调用。
  3. Thread类的start办法是用于启动相干线程的,启动一个线程的本质是申请java虚拟机运行相应的线程,而这个线程具体什么时候运行是由线程调度器决定的.因而,尽管start办法被执行了,然而并不意味着这个线程就开始运行了,它可能稍后运行,也可能永远不运行.
  4. Thread中罕用的两个结构器是:Thread()和Thread(Runnable target),这两种创立线程的形式如下:

    1. 定义Thread类子类的形式创立线程

      public class WelcomeApp {
      
        public static void main(String[] args) {
          // 创立线程
          Thread welcomeThread = new WelcomeThread();
      
          // 启动线程
          welcomeThread.start();
      
          // 输入“以后线程”的线程名称
          System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName());
        }
      }
      
      // 定义Thread类的子类
      class WelcomeThread extends Thread {
      
        // 在该办法中实现线程的工作解决逻辑
        @Override
        public void run() {
          System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName());
        }
      }
      
    2. 实现Runnable接口的形式创立线程

      public class WelcomeApp1 {
      
        public static void main(String[] args) {
          // 创立线程
          Thread welcomeThread = new Thread(new WelcomeTask());
      
          // 启动线程
          welcomeThread.start();
          // 输入“以后线程”的线程名称
          System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName());
      
        }
      
      }
      
      class WelcomeTask implements Runnable {
        // 在该办法中实现线程的工作解决逻辑
        @Override
        public void run() {
          // 输入“以后线程”的线程名称
          System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName());
        }
      
      }
  5. 不论应用以上哪种形式运行,一旦线程的run办法执行完结,相应线程的运行也就完结了,运行完结的线程所占的资源会如同其它java对象一样被java虚拟机垃圾回收。
  6. Thread的实例只能start一次,若屡次调用一个实例的start()会抛出IllegalThreadStateException异样。
  7. 能够通过Thread.currentThread()获取以后线程,进而能够对其进行属性设置或获取它的相干信息,例如:

    Thread.currentThread().setName("线程A");
    Thread.currentThread().getName();
  8. 上述中,线程的run办法个别由java虚拟机调用,然而,线程也是一个Thread类的一个实例其次run办法也是由public修饰符润饰,所以run办法也能被间接调用,然而个别不会这么做,违反咱们床架线程的初衷。

    public class WelcomeApp {
    
      public static void main(String[] args) {
        // 创立线程
        Thread welcomeThread = new WelcomeThread();
        // 启动线程
        welcomeThread.start();
        // 输入“以后线程”的线程名称
        System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName());
        welcomeThread.run();
      }
    }
    
    // 定义Thread类的子类
    class WelcomeThread extends Thread {
    
      // 在该办法中实现线程的工作解决逻辑
      @Override
      public void run() {
        System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName());
      }
    }
    ==================后果==================
    1.Welcome! I'm main.
    2.Welcome! I'm Thread-0.
    2.Welcome! I'm main.
    
  9. 线程的属性

    属性 属性类型及用处 只读 重要注意事项
    编号
    ID
    用于标识不同的线程,不同的线程领有不同的编号 某个编号的线程运行完结后,该编号可能被后续创立的线程应用。不同线程领有的编号尽管不同,然而这种编号的唯一性只在Java虚拟机的一次运行无效。也就是说重启一个Java虚拟机(如重启Web服务器)后,某些线程的编号可能与上次Java虚拟机运行的某个线程的编号一样,因而该属性的值不适宜用作某种惟一标识,特地是作为数据库中的惟一标识(如主键)
    名称
    Name
    用于辨别不同的线程。默认值与线程的编号无关,默认值的格局为:Thread-线程编号,如Thread-0 Java并不禁止咱们将不同的线程的名称属性设置为雷同的值。尽管如此,设置线程的名称属性有助于代码调试和问题定位
    线程类别
    Daemon
    值为true示意相应的线程为守护线程,否则示意相应的线程为用户线程。该属性的默认值与相应线程的父线程的该属性的值雷同,在失常进行java程序时,当有用户线程还没执行完虚拟机不会立刻进行,会期待其执行结束,然而如果只有守护线程还没执行完则不会阻止虚拟机进行,这阐明守护线程通常用于执行一些重要性不是很高的工作,例如监督其它线程的 该属性必须在相应线程启动之前设置,即对setDaemon办法的调用必须在对start办法的调用之前,否则setDaemon办法会抛出IllegalThreadStateException异样。负责一些要害工作解决的线程不合适设置为守护线程
    优先级
    Priority
    该属性实质上是给线程调度器的提醒,用于示意应用程序心愿哪个线程可能优先得以运行。Java定义了1~10的10个优先级。默认值个别为5。对于具体的一个线程而言,其优先级的默认值与其父线程(创立该线程的线程)的优先级值相等 个别应用默认优先级即可。不恰当地设置该属性值可能导致重大的问题(线程饥饿)
  10. 线程办法

    办法 性能 备注
    static Thread
    currentThread()
    返回以后线程,即以后代码的执行线程(对象) 同一段代码对Thread.currentThread()的调用,其返回值可能对应着不同的线程(对象)
    void run() 用于实现线程的工作解决逻辑 该办法是由Java虚拟机间接调用的,个别状况下应用程序不应该调用该办法
    void start() 启动相应线程 该办法的返回并不代表相应的线程曾经被启动。一个Thread实例的start办法只可能被调用一次,屡次调用会导致异样的抛出
    void join() 期待相应线程运行完结 若线程A调用线程B的join办法,那么线程A的运行会被暂停,直到线程B运行完结
    static void yield() 使以后线程被动放弃其对处理器的占用,这可能导致以后线程被暂停 这个办法是不牢靠的。该办法被调用时以后线程可能依然持续运行(视零碎以后的运行状况而定)
    static void sleep(long millis) 使以后线程休眠(暂停运行)指定的工夫

Thread和Runnable的关系

  1. Thread类实现Runnable接口

    public class Thread implements Runnable{}
    
    
  2. Runnable是一个interface且其中只有一个办法,所以实现Runnable的类要从新run办法。
  3. 两种形式执行工作逻辑的过程

    • 实现Runnable接口,重写run办法

      class WelcomeTask implements Runnable {
        @Override
        public void run() {
          //工作逻辑 
        }
      }
      
      new Thread(new WelcomeTask()).start();

      WelcomeTask实例在Thread中的传递过程,它最终会被赋值给Thread中的一个target成员变量

      private Runnable target;

      具体过程如下:
      1.有参构造函数,生成一个ThreadName,例如:Thread-0

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

      2.进入第一个初始化函数,这外面无需关注其它参数,因为还有其它构造方法会调用init(…)

      private void init(ThreadGroup g, Runnable target, String name,long stackSize){
          init(g, target, name, stackSize, null, true);
      }

      3.第二层初始化函数,行将target赋值

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

      4.Thread实例调用start()办法

      public synchronized void start() {
          //threadStatus != 0代表这个Thread实例曾经被start()过了,所以会抛出异样
          if (threadStatus != 0)
              throw new IllegalThreadStateException();
          ...
          try {
              //最终会调用本地办法start0()来启动这个线程
              start0();
              ...
          } finally {
              ...
          }
      }

      5.本地办法启动线程,行将线程交给虚拟机的线程调度器

      private native void start0();

      6.线程调度器执行线程工作逻辑

      //启动线程后,调度器会帮忙咱们运行执行线程run()办法,即工作逻辑
      //如果target != null的时候会调用WelcomeTask中实现的工作逻辑,否则什么都不会执行
      public void run() {
          if (target != null) {
              target.run();
          }
      }
      
    • 继承Thread类,重写run办法

      class WelcomeThread extends Thread {
           @Override
           public void run() {
             //工作逻辑
           }
      }
          
      new WelcomeThread().start();
      ...
      //任务调度器间接调用WelcomeThread中实现的工作逻辑
  4. 两种形式的区别

    • 面向对象角度:一种是基于继承实现extends Thread,一种是基于组合new Thread(new Runable()),组合绝对与继承来说耦合性更低。
    • 对象共享的角度:一个CountingTask实例能够被多个线程共享所以可能呈现资源竞争问题。

      class CountingThread extends Thread {
          int count = 0;
          @Override
          public void run() {
              for (int i = 0; i < 100; i++) {
                  i++;
              }
          }
          System.out.println("count:" + count);
      }
      
      class CountingTask implments Runnable {
          int count = 0;
          @Override
          public void run() {
              for (int i = 0; i < 100; i++) {
                  i++;
              }
          }
          System.out.println("count:" + count);
      }
      
      public static void main(String[] args) {
          Thread thread;
          CountingTask task = new CountingTask();
          for(int i = 0;i < 10;i++){
              thread = new Thread(task);
              thread.start();
          }
          for(int i = 0;i < 10;i++){
              thread = new CountingThread();
              thread.start();
          }
      }

线程的生命周期

  1. New(新创建)
    Thread thread = new Thread();
    此时线程只是备new进去并没有开始执行。
  2. Runnable(可运行)
    thread.start();
    1.ready:还没有被分配资源 。
    2.running:正在执行 。
  3. 阻塞
    1.Blocked(阻塞) 没有获取被synchronized爱护的代码的锁 。
    2.Waiting(期待)

     1.Object.wait(); 
         - o.notify()/o.notifyAll()
     2.Thread.join(); 
         - join线程完结/被中断 
     Blocked与Waiting的区别是Blocked是在期待开释某个资源,Waiting是在期待达到某个条件 。
  4. Time Waiting(计时期待) 设置了工夫参数的一些阻塞 。
    1.Thread.sleep(m);

      - 工夫超时/join的过程完结/被中断 。

    2.Object.wait(m)

     - 工夫到/o.notify()/o.notifyAll() 

    3.Thread.join(m)

     - 工夫超时/join的过程完结/被中断 。
  5. Terminated(终止)
    1.run办法失常执行结束 。
    2.呈现没有捕捉的异样,意外终止。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理