zoukankan      html  css  js  c++  java
  • Java并发编程基础01-线程管理

    线程创建、运行和设置

    (1)Java中创建线程的主要两种方式

    • 直接继承Thread类,然后重写run()方法。
    • 构建一个实现Runnable接口的类并重写run()方法,然后创建该类的实例对象,并以其作为构造参数去创建Thread类的对象。建议首选这种方法,因为它可以带来更多的扩展性。

    (2)Thread类的主要属性

    • ID:该属性存储了每个线程的唯一标识符。
    • Name:该属性存储了线程的名字。
    • Priority:该属性存储了Thread对象的优先级。线程优先级的范围为1~10,其中1表示最低优先级,10表示最高优先级。修改线程优先级不能保证能发生任何事情,仅仅代表一种可能性
    • Status:该属性保存了线程的状态。在Java中,线程有6种状态——Thread.State枚举中定义这些状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。
    NEW:线程已经创建完毕但未开始执行。
    RUNNABLE:线程正在JVM中执行。
    BLOCKED:线程处于阻塞状态,并且等待获取监视器。
    WAITING:线程在等待另一个线程。
    TIMED_WAITING:线程等待另一个线程一定的时间。
    TERMINATED:线程执行完毕。
    

    (3)每个Java应用程序都至少有一个执行线程。在程序启动时,JVM会自动创建执行线程运行程序的main()方法。

    (4)一个Java程序将在所有非守护线程完成后结束。不会去等待守护线程,当所有非守护线程完成,进程结束!

    (5)如果一个线程调用System.exit()命令去结束程序,那么所有线程将会终止各自的运

    行。

    线程中断

    (1)使用task.interrupt()方法对线程进行中断【当调用一个线程对象的interrupt()方法时,中断状态属性将修改为true】,但是需要线程代码进行响应。

    (2)利用了中断标识状态来进行自我结束的方法,继承Thread,在程序中判断isinterrupted()是否为true,来自行解决线程生命

    (3)如果没有继承Thread,也可以在Runnable中使用Thread.interrupted()静态方法来判断

    (4)在Thread类中,还有一个静态方法interrupted(),也能用来检测当前线程是否已被中断。isInterrupted()方法不会修改线程的是否中断属性,而interrupted()方法会将中断属性设置为false。

    (5)Java提供了InterruptedException异常,可以在检测到线程中断后抛出该异常,并在run()方法中捕获它。【使用异常方式的优势就是指,可以捕获异常,知晓线程是被中断的

    (6)当线程结束时,为什么isinterrupted会为false?应该是线程自己结束时会将中断状态复原为false

    线程休眠和唤醒

    (1)线程休眠的经典方法:Thread类的sleep()方法。该方法接收一个long类型的参数——该参数是线程将要暂停的时长。【静态方法,Thread.sleep()毫秒为单位】

    注:当调用sleep()方法时,线程释放CPU资源,停止执行指定的时间。在这段时间里,线程并不消耗CPU时间,因此CPU可以执行其他任务。

    (2)自定义休眠时间单位:可以使用TimeUnit枚举元素的sleep()方法。该方法调用当前Thread类的sleep()方法,使当前线程进入休眠。

    (3)当线程在休眠中发生中断时,该方法会立即抛出一个InterruptedException异常,而不会等到休眠时间结束。

    (4)yield方法也可以做到是线程释放CPU资源,该方法告知JVM当前线程可以为其他任务放弃CPU资源。JVM并不保证一定会响应该请求

    在主线程中等待线程执行完成

    (1)当调用一个线程对象的join()方法时,发起调用的线程将会暂停,直到线程对象执行结束。注:

    • join()这样做会阻塞主线程,但是好处也是有的,例如初始化任务作为单独线程,则必须等待其结束
    • 先要开始线程,才能用join等待
      图片

    (2)join方法会抛出InterruptedException异常,但是触发条件并不是对其进行中断时,在线程join期间,对其进行中断,并不会抛出中断异常!

    守护线程的创建和运行

    (1)设置守护线程的方法:setDaemon()方法只能在start()方法之前调用,一旦线程开始执行,其daemon状态便不可修改。

    (2)通过isDaemon()方法可以检查线程是一个守护线程(此时方法返回true)还是一个非守护线程(此时方法返回为false)。

    (3)守护线程通常是一个无限循环程序,最典型的应用是:JVM垃圾回收器;注意,JVM并不会等待守护线程执行完成,当JVM发现程序只有守护线程存在时,会将其杀死,并结束程序。

    处理线程中的非受查异常

    (1)Java提供了用于处理线程对象中抛出的非检查异常机制,该机制不是类似于try-catch机制,而是一种处理机制。一旦发生非受查异常,会立刻结束线程,有异常处理器就会转入异常处理器执行。

    (2)要使用该机制,必须实现一个处理非检查异常的类。该类必须实现UncaughtExceptionHandler接口,并实现接口中声明的uncaughtException()方法。使用thread.setUncaughtExceptionHandler(new ExceptionHandler())方法来设置处理器。

    图片

    (3)如果线程对象没有配置非受查异常处理器,则JVM会在控制台中打印出异常信息栈,然后结束异常抛出线程的执行。【而配置了非受查异常处理器,也非常鸡肋,只是可以对异常进行处理而已,线程还是会在异常处结束运行】

    (4)Thread类中还定义了另一个用于处理非受查异常的方法,即静态方法setDefault-

    UncaughtExceptionHandler()。该方法可以为应用中所有线程对象设置默认的非受查异常处理器。

    (5)JVM为非受查异常寻找处理器的顺序

    1、线程对象的非受查异常处理器。

    2、线程组的非受查异常处理器。

    3、默认的异常处理器

    使用线程本地变量

    (1)ThreadLocal类,实现该类的一个实例,并复写initalValue方法

    // 原始写法
    ThreadLocal<Date> a = new ThreadLocal<Date>() {
        @Override
        protected Date initialValue() {
            return new Date();
        }
    };
    
    // 简单写法:
    ThreadLocal<Date> a = ThreadLocal.withInitial(() -> new Date());
    

    注:第一次访问线程本地变量时,若与该线程对象关联的属性值不存在,则将会触发
    initialValue()方法,它会为该属性赋值并返回初始值。

    (2)InheritableThreadLocal类提供了线程本地变量的继承机制

    线程分组

    (1)一个ThreadGroup对象可以由一组线程对象或者其他ThreadGroup对象组成,形成一个线程的树形结构。

    注:

    • ThreadGroup类不是使用组合模式提供组织
    • 如果组1里有其他线程组,则组1会自动屏蔽所有的线程对象,成为线程组的组。
    • 线程组的优先级高于线程对象

    (2)获取处理器内核数的方法:

    使用Runtime类的availableProcessors()方法[使用Runtime类的静态方法getRuntime()得到当前应用的Runtime对象],可以得到JVM中可用的处理器数。

    (3)创建线程组的范式:

    创建一个名为MyThreadGroup的类,并继承ThreadGroup类进行扩展。ThreadGroup类没有无参构造器,因此必须声明一个拥有一个参数的构造器。为了处理线程组抛出的异常,还需要重写uncaughtException()方法

    public class MyThreadGroup extends ThreadGroup {
       /**
        * Constructor of the class. Calls the parent class constructor
        * 
        * @param name
        */
       public MyThreadGroup(String name) {
          super(name);
       }
       /**
        * Method for process the uncaught exceptions
        */
       @Override
       public void uncaughtException(Thread t, Throwable e) {
          // Prints the name of the Thread
          System.out.printf("The thread %s has thrown an Exception
    ", t.getId());
          // Print the stack trace of the exception
          e.printStackTrace(System.out);
          // Interrupt the rest of the threads of the thread group
          System.out.printf("Terminating the rest of the Threads
    ");
          interrupt();
       }
    }
    

    (4)线程关联线程组:

    Thread t = new Thread(threadGroup, task);
    

    (5)将threadgroup中的线程转化为线程数组的方法

    Thread[] threads = new Thread[threadGroup.activeCount()];
    threadGroup.enumerate(threads);
    

    使用工程创建线程

    (1)线程工厂的核心代码:

    ThreadFactory接口只有一个名为newThread()的方法。该方法接收一个Runnable对象作为参数,并返回一个Thread对象。实现一个ThreadFactory接口时,必须覆盖newThread()方法。

    (2)使用工厂的好处:

    • 记录线程的创建信息
    • 统一管理某一类线程的创建
  • 相关阅读:
    Blend操作入门: 别站在门外偷看,快进来吧!
    Egyee,这个世界很美丽
    在Windows Azure中使用自己的域名
    Windows Azure服务购买,收费,使用注意事项及学习资料推荐
    Silverlight怎样加载xap中的各个程序集
    WCF RIA Service随想
    Silverlight布局,也许不止这么多(附照片墙示例及源码)
    An introduction to variable and feature selection
    Compressed Learning
    Robust PCA (摘抄)
  • 原文地址:https://www.cnblogs.com/doubest/p/15380045.html
Copyright © 2011-2022 走看看