Java多线程学习-1

  1. 创建Java线程
    Java中Thread类采用了模板设计模式,像下面的方式创建一个线程,不会做任何操作,在启动之后会迅速退出。
   // 创建一个Thread对象,但并没有创建一个线程
    Thread thread = new Thread();
   // 启动线程
    thread.start(); 

Thread类中的run方法做为执行单元,一般在创建具体的业务线程的时候都必须要重写run方法,以实现真正的业务逻辑。

引入策略模式(Runnable接口)使得业务逻辑与线程的控制逻辑分离后,业务逻辑更加清晰。所以大多数情况都会采用实现Runnable的方式实现Java的多线程。

public class MyRunnable implements Runnable {
    public void run() {
       System.out.println("here is the system logic");
   }
}

Thread thread = new Thread(new MyRunnable());
thread.start();
  1. Thread 的构造函数


    Thread API.jpg

    从上面可以看到Thread的构造函数,主要有Runnable(业务逻辑),ThreadGroup(线程组),name(线程名)以及stackSize(线程栈)四个参数。最主要的参数业务逻辑并不需要多做任何介绍,线程组和线程名两个参数有必要进行一下介绍。

2.1 线程名
为一个业务线程取一个合适的名字,当业务在出现问题的时候可以快速定位到问题,那么如果线程没有取名的话,默认线程会以”Thead-“做为前缀和一个自增的自然数做为线程名(注意是线程调用start方法的顺序递增,而不是创建Thread对象的顺序)。

线程名的修改,在线程启动之前是可以通过setName方法修改的,不过在线程启动之后,线程名将不能再修改。

2.2 ThreadGroup
在介绍ThreadGoup之前,首先要介绍一下Thread的父子关系,通过分析Thread类的init方法的源码我们可以发现,Thread的parent为创建线程的线程做为父线程;如果在创建线程之前没有指定ThreadGroup时,会将父线程的ThreadGroup做为当前线程的ThreadGroup;子线程将父线程的priority和daemon做为自己的priority和daemon。

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;

      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();
  }
  1. Deamon 线程
    在搞清楚Deamon之前,首先要搞清楚一个问题:JVM虚拟机会在什么时候退出?
    在JVM虚拟机官方文档中: The JVM will exits when the only threads running are all daemon threads. (当虚拟机的所有线程只有守护线程时,虚拟机将会退出。)

3.1 怎样创建一个daemon thread
在线程调用start之前,通过setDaemon(true)方法可以将线程设置为守护线程。注意在线程启动之后,调用setDaemon会抛出异常。通过isDaemon方法可以判断这个线程是否是守护线程。

以上仅仅是线程的最基本的属性,在业务中使用多线程,我们还需要进一步学习线程的更多特性和API。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容