Java并发编程2

(接上文)

2.3 总结

在本章节并发编程核心中,我们认识了进程和线程、线程的执行方式(串行、并发)和执行时机(同步、异步);了解了如何创建线程进程的生命周期;通过Thread源码学习到其中使用的两种设计模式:模板方法设计模式和策略模式

三、深入理解Thread

3.1 Thread构造方法

3.1.1 不含ThreadGroup的构造方法

https://img-blog.csdnimg.cn/e18a19d9f8e14528970f2dd2f4e037b6.png
先认识Tread前四种构造方法
这里提一下创建线程时的命名规则,当没有设定线程名称时,线程名会按照Thread-0、Thread-1、Thread-2…累计命名,不会因中间出现的自定义名称的线程而发生编号缺失(除非将默认名称创建后,将该线程名称修改)。原因见下面源码
在这里插入图片描述
在这里插入图片描述

3.1.2 ThreadGroup

顾名思义,即线程组,用来标识同一组线程。作用此处先不讲。
可以通过以下构造方法创建ThreadGroup:

ThreadGroup threadGroup = new ThreadGroup("myThread");  // 创建名为myThread的线程组
// 还有一种指定父线程组的方式,这里不展示。

Tips:
main线程所属线程组名为main;
当创建线程时若不指定线程组,则会将父线程(创建该线程的线程)的线程组作为该线程的线程组,见源码:(带有ThreadGroup参数的构造方法最终会调用如下init()方法)

/**
    * Initializes a Thread.
    *
    * @param g the Thread group
    * @param target the object whose run() method gets called
    * @param name the name of the new Thread
    * @param stackSize the desired stack size for the new thread, or
   *        zero to indicate that this parameter is to be ignored.
   * @param acc the AccessControlContext to inherit, or
   *            AccessController.getContext() if null
  * @param inheritThreadLocals if {@code true}, inherit initial values for
   *            inheritable thread-locals from the constructing thread
   */
   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;

       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();    // 当前线程线程组设置为父线程线程组
           }
       }

3.1.2 stackSize

    /*
     * The requested stack size for this thread, or 0 if the creator did
     * not specify a stack size.  It is up to the VM to do whatever it
     * likes with this number; some VMs will ignore it.
     * 设置当前线程的栈容量,不指定则为0。
     * 该数字的设置在一个虚拟机中可能被忽略,而由虚拟机自己决定。
     */
    private long stackSize;

一般情况下,不会主动设置该参数

3.2 守护线程

JVM进程中,当存在任意一个非守护线程时,JVM不会停止;仅当进程中都是守护线程时,JVM才会停止。
在这里插入图片描述

守护线程的例子:
JVM垃圾回收线程。在main线程仍然运行时,垃圾回收线程始终保持后台运行,为main提供垃圾回收服务;当main线程结束(程序执行结束),此时没有了非守护线程,JVM关闭。

3.3 总结

本节主要了解了Thread的多种构造方法、其中TreadGroup和stackSize的含义以及守护线程的概念。

四、ThreadAPI介绍

4.1 sleep()

    /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     * 立即使当前线程暂停执行指定时间,暂停时间取决于系统定时器和调度器的精准度
     * 此线程不会失去monitor的持有权(以后介绍)
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public static native void sleep(long millis) throws InterruptedException;

注:
在实际开发和使用场景中,更多地是使用TimeUnit替代Thread.sleep()
在这里插入图片描述
使用TimeUnit可使时间设定值可读、更有意义。

4.2 yield()

    /**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     * 提醒调度器当前线程可以让出CPU占用权。
     * 调度器也可以忽略。
     *
     * <p> Yield is a heuristic attempt to improve relative progression
     * between threads that would otherwise over-utilise a CPU. Its use
     * should be combined with detailed profiling and benchmarking to
     * ensure that it actually has the desired effect.
     * yield方法尝试解决线程过度占用CPU的问题,以提高执行效率。
     * 应该结合详细的配置和标准使用yield,以达到预期效果。
     *
     * <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     * yield不常用。
     * yield可用于调试和测试,找出竞争场景下的bug。
     * 设计并发控制组件也可用yield。
     */
    public static native void yield();

yield和sleep
注:在JDK1.5之前,yield内部实际使用调用了sleep(0)。

  1. yield 只是对CPU 调度器的一个提示,如果 CPU调度器没有忽略这个提示,它会导致当前线程让出CPU占用权,发生线程上下文的切换;
  2. sleep 会使线程短暂 block,会在给定的时间内试放 CPU 资源;
  3. yield 会使 Running状态的 Thread 进入Runnable 状态(如果 CPU 调度器没有忽略这个提示的话);sleep 几乎百分之百的完成了给定时间的休眠,而 yield 的提示并不能一定保证。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值