美文网首页
Java并发编程-1

Java并发编程-1

作者: 梦工厂 | 来源:发表于2018-03-21 19:24 被阅读75次

    基本知识
    一 线程优先级
    二 线程的状态
    三 线程函数
    四 线程间通信

    参考:java并发编程的艺术


    一 线程优先级

    • 线程优先级决定线程可以多分或少分配一些处理器资源,时间片的数量;
    • 针对频繁阻塞(休眠或IO)的线程需要设置较高优先级,占用CPU时间短。
      针对偏重计算(较多CPU时间或偏运算)设置较低优先级,确保不会独占。
    • Java默认优先级为5,范围1-10。

    线程优先级不能作为程序正确性的依赖,因为OS可以完全不理会Java的优先级设置。

    二 线程的状态

    1. 状态说明
      • 初始状态NEW :A thread that has not yet started is in this state.
      • 运行状态RUNNABLE:A thread executing in the Java virtual machine is in this state.(就绪+运行)
      • 阻塞状态BLOCKED thread that is blocked waiting for a monitor lock is in this state. (synchronized块/方法)
      • 等待状态WAITING:A thread that is waiting indefinitely for another thread to perform a particular action is in this state.(其他线程通知notify、notifyAll或中断)
      • 超时等待状态TIMED_WAITING :A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state. (指定时间内可以返回的等待状态)
      • 终止状态TERMINATED:A thread that has exited is in this state.
    2. 状态转换图

      阻塞状态是线程阻塞在进入synchronized关键字修饰的方法块或代码块时的状态,
      但是阻塞在concurrent包中lock接口的线程状态是等待状态,因为concurrent包中lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。

    三 线程函数
    1. Daemon线程 后台线程

         Thread daemon = new Thread(new DaemonRunner());
         daemon.setDaemon(true);//启动之前设置
         daemon.start();
      

      如果java虚拟机中不存在非Daemon线程时,java虚拟机将会推出。
      JVM退出时,所有的Daemon线程都会被立即停止。finally块代码并不会执行;

    2. 主线程结束和子线程结束之间的关系 链接
      情况1:正常情况下,主线程启动了子线程,主线程、子线程各自执行,彼此不受影响。


      情况2:需求是主线程执行结束,由主线程启动的子线程都结束

      情况3:需求是子线程执行结束,主线程等待启动的子线程都结束之后再结束


    3. 中断标记 链接

      • 一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。
        Thread.stop(不保证资源的正确释放), Thread.suspend(暂停时不释放锁), Thread.resume 都被废弃了。

      • 中断可以理解为线程的一个标志位,表示该线程是否被求他线程进行了中断操作。
        相当于其它线程打了个中断招呼,具体自己中断还是继续运行,由自己来决定。

      • 具体来说,当对一个线程,调用 interrupt() 时,
        ① 如果线程处于等待状态(例如处于sleep, wait, join)那么线程将立即退出被等待状态,并抛出一个InterruptedException异常,仅此而已。被锁时不响应;
        ② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。

      • interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。
        也就是说,一个线程如果有被中断的需求,那么就可以这样做。
        ① 在正常运行任务时,经常检查本线程的中断标志位 isInterrupted(),如果被设置了中断标志就自行停止线程。
        ② 在调用等待方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)

      • Thread.interrupted()会清除标志位,并不是代表线程又恢复了,可以理解为仅仅是代表它已经响应完了这个中断信号然后又重新置为可以再次接收信号的状态。
        InterruptedException抛出时,也会清楚中断标记位。

    4. Thread.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.

    四 线程间通信
    1. 共享变量
      共享变量在共享内存中,但是每个线程可以有一份拷贝,加速程序执行,所以线程看到的变量不一定是新的。

      • 关键字 volatile :访问必须从共享内存获取,修改必须同步刷新回共享内存,保证内存可见性。
      • 关键字 synchronized :同步块或方法,线程的访问是同步互斥的。
    2. 等待/通知机制
      wait() :释放对象的锁,变为Waiting状态;wait返回的前提是notify线程释放锁,自己拿到对象的锁;
      wait(long) :返回也需要锁;
      notify() :通知一个等待线程由等待队列进入同步队列,Waiting变Blocking;
      notifyAll() :通知所有等待的线程;


      等待通知机制依赖于同步机制,目的就是确保等待线程返回时可以感知到通知线程对变量所做的修改。
      1.等待方
      synchronized (obj) {
            while (condition does not hold)
                obj.wait();
            ... // Perform action appropriate to condition
      }
      2.通知方
      synchronized (obj) {
            改变条件
            obj.notify();
      }
      

      thread.join() :等待线程结束,内部使用wait-notify

      public final synchronized void join(long millis) throws InterruptedException {
          long base = System.currentTimeMillis();
          long now = 0;
          if (millis < 0) {
              throw new IllegalArgumentException("timeout value is negative");
          }
          if (millis == 0) {
              while (isAlive()) {
                  wait(0);
              }
          } else {
              while (isAlive()) {
                  long delay = millis - now;
                  if (delay <= 0) {
                      break;
                  }
                  wait(delay);
                  now = System.currentTimeMillis() - base;
              }
          }
      }
      
    3. 管道输入输出流

      管道IO与文件IO或网络IO不同,主要用于线程之间的数据传输,传输的媒介为内存
      面向字节:PipedInputStream、PipedOutputStream
      面向字符流:PipedReader,PipedWriter

      PipedReader in = new PipedReader();
      PipedWriter out = new PipedWriter();
      out.connect(in);//输入流和输出流需要连接,否则异常
      

    @梦工厂2018.3.21

    相关文章

      网友评论

          本文标题:Java并发编程-1

          本文链接:https://www.haomeiwen.com/subject/bvknqftx.html