zoukankan      html  css  js  c++  java
  • 《Java核心技术(卷1)》笔记:第12章 并发

    线程

    1. (P 552)多进程多线程的本质区别:每一个进程都拥有自己的一整套变量,而线程共享数据

    2. (P 555)线程具有6种状态

      • New(新建):使用new操作符创建线程时
      • Runnable(可运行):调用start方法
      • Blocked(阻塞)
      • Waiting(等待)
      • Timed waiting(计时等待)
      • Terminated(终止):run方法正常退出、没有捕获异常
      image-20200630154201750
    3. (P 558)interrupt方法用来请求终止一个线程。当对一个线程调用interrupt方法时,就会设置线程的中断状态。每个线程都应该不时地检查这个标志,以判断线程是否被中断

    4. (P 559)如果线程被阻塞,就无法检查中断状态,因此引入InterruptedException异常。当在一个被sleepwait调用阻塞的线程上调用interrupt方法时,那个阻塞调用将被一个InterrupedtException异常中断

    5. (P 559)如果设置了中断状态,此时倘若调用sleep方法,它不会休眠。实际上,它会清除中断状态并抛出InterruptedException。因此,如果循环里调用了sleep,不要检测中断状态,而应当捕获InterruptedException异常

    6. (P 560)interruptedisInterrupted以及interrupt方法的区别:

      方法 性质 作用 影响
      interrupted Thread的静态方法 检查当前线程是否被中断 会清除该线程的中断状态
      isInterrupted Thread的实例方法 测试线程是否被中断 不会改变中断状态
      interrupt Thread的实例方法 向线程发送中断请求 会设置线程的中断状态
    7. (P 561)守护线程:唯一用途是为其他线程提供服务,当只剩下守护线程时,虚拟机就会退出。可通过setDaemon方法将线程设为守护线程

    8. (P 561)线程的run方法不能抛出任何检查型异常,在线程死亡之前,异常会传递到一个用于处理未捕获异常的处理器(必须实现Thread.UncaughtExceptionHandler接口)

      方法 性质 作用
      setUncaughtExceptionHandler Thread的实例方法 为任何线程安装一个处理器
      setDefaultUncaughtExceptionHandler Thread的静态方法 为所有线程安装一个默认的处理器

    同步

    1. (P 568)Java提供的两种可防止并发访问代码块的机制:

      • synchronized关键字

      • ReentrantLock类(重入锁)

        myLock.lock();	// 一个ReentrantLock对象
        try {
            ...
        } finally {
            myLock.unlock();	// 必须放在finally里,不能使用try-with-resources
        }
        
    2. (P 570)重入(reentrant)锁:线程可以反复获得已拥有的锁,被一个锁保护的代码可以调用另一个使用相同锁的方法。注意确保临界区中的代码不要因为抛出异常而跳出临界区

    3. (P 572)一个锁对象可以有一个或多个相关联的条件对象,可以使用newCondition方法获得一个条件对象。

      方法 性质 作用
      newCondition ReentrantLock的实例方法 获得一个条件对象
      await Condition的实例方法 当前线程现在暂停,并放弃锁
      signalAll Condition的实例方法 解除等待这个条件的所有线程的阻塞状态
      signal Condition的实例方法 随机选择一个线程解除其阻塞状态

      使用形式:

      class A {
          private var lock = new ReentrantLock();
          private Condition condition;
          ...
          
          private A() {
              ...
              condition = lock.newCondition();
          }
          
          private someMethod() {
              lock.lock();
              try {
                  ...
                  while(!(OK to proceed)) {	// await调用通常放在循环中
                      condition.await();
                  }
                  ...
                  condition.signalAll();	// signalAll只是通知等待的线程:现在有可能满足条件,值得再次检查条件
                  						// 只要一个对象的状态有变化,而且可能有利于等待的线程,就可以调用signalAll
                  						// signalAll只是解除等待线程的阻塞,使这些线程可以在当前线程释放锁之后竞争访问对象
              } finally {
                  lock.unlock();
              }
          }
          
          ...
      }
      
    4. (P 576)Java中的每个对象都有一个内部锁只有一个关联条件)。如果一个方法声明时有synchronized关键字,那么对象的锁将保护整个方法

      方法 性质 作用 等价于
      wait Object的实例方法 将一个线程增加到等待集中 await
      notify/notifyAll Object的实例方法 解除等待线程的阻塞 signal/signalAll
    5. (P 577)将静态方法声明为同步也是合法的,如果调用这样一个方法,它会获得相关类对象(Class对象)的内部锁

    6. (P 577)内部锁和条件存在一些限制

      • 不能中断一个正在尝试获得锁的线程
      • 不能指定尝试获得锁时的超时时间
      • 每个锁仅有一个条件可能是不够的
    7. (P 579)同步块:

      synchronized(obj) {	// 会获得obj对象的锁
          ...
      }
      
    8. (P 580)监视器的特性:

      • 监视器是只包含私有字段的类
      • 监视器类的每个对象有一个关联的
      • 所有方法有这个锁锁定
      • 锁可以有任意多个相关联的条件
    9. (P 581)volatile关键字为实例字段的同步访问提供了一种免锁机制,volatile变量不能提供原子性

      • 另一种安全访问共享字段的情况:将字段声明为final
    10. (P 582)java.util.concurrent.atomic包中有很多类使用了很高效的机器级指令来保证其他操作的原子性

    11. (P 586)线程局部变量:ThreadLocal

      public static final ThreadLocal<SimpleDateFormat> dataFormat = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
      // 在一个给定线程中首次调用get时,会调用构造器中的lambda表达式
      // 在此之后,get方法会返回属于当前线程的那个实例
      String dateStamp = dataFormat.get().format(new Date());
      

    线程安全的集合

    1. (P 589)阻塞队列(blocking queue):addelementofferpeekpollputremovetake

    2. (P 595)高效的映射、集和队列:java.util.concurrent包提供了ConcurrentHashMapConcurrentSkipListMapConcurrentSkipListSetConcurrentLinkedQueue

    3. (P 602)同步包装器(synchronization wrapper):任何集合类都可以通过使用同步包装器变成线程安全的

      List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E>());
      Map<K, V> synchHashMap = Collections.synchronizedMap(new HashMap<K, V>());
      

    线程池

    1. (P 603)CallableRunnable类似,但是有返回值,只有一个call方法

    2. (P 604)Future保存异步计算的结果

    3. (P 604)执行Callable的一种方法是使用FutureTask,它实现了FutureRunnable接口

      Callable<Integer> task = ...;
      var futureTask = new FutureTask<Integer>(task);
      var t = new Thread(futureTask);		// it's a Runnable
      t.start();
      ...
      Integer result = futureTask.get();	// it's a Future
      
    4. (P 605)执行器(Executors)类有许多静态工厂方法,用来构造线程池

    5. (P 606)使用线程池时所做的工作:

      1. 调用Executors类的静态方法newCachedThreadPoolnewFixedThreadPool
      2. 调用submit提交RunnableCallable对象
      3. 保存好返回的Future对象,以便得到结果或者取消任务
      4. 当不想再提交任何任务时,调用shutdown
    6. (P 607)控制任务组

      方法 性质 作用 备注
      invokeAny ExecutorService的实例方法 提交一个Callable对象集合中的所有对象,并返回某个已完成任务的结果
      invokeAll ExecutorService的实例方法 提交一个Callable对象集合中的所有对象,并返回表示所有任务答案的一个Future对象列表 这个方法会阻塞,直到所有任务都完成
    7. (P 612)fork-join框架:专门用来支持计算密集型任务,假设有一个处理任务,它可以很自然地分解为子任务

    异步计算

    1. (P 615)CompletableFuture类实现了Future接口,它提供了获得结果的另一种机制。你要注册一个回调,一旦结果可用,就会(在某个线程中)利用该结果调用这个回调(与之不同的是,Future中的get方法会阻塞)
    2. (P 615)Supplier<T>Callable<T>:都描述了无参数而且返回值类型为T的函数,不过Supplier函数不能抛出检查型异常

    进程

    1. (P 628)Process类在一个单独的操作系统进程中执行一个命令,允许我们与标准输入、输出和错误流交互。ProcessBuilder类则允许我们配置Process对象
    2. (P 631)ProcessHandle接口:要获得程序启动的一个进程的更多信息,或者想更多地了解你的计算机上正在运行的任何其他进程,可以使用ProcessHandle接口
    3. (P 631)得到ProcessHandle的4种方式:
      • 给定一个Process对象pp.toHandle()会生成它的ProcessHandle
      • 给定一个long类型的操作系统进程IDProcessHandle.of(id)可以生成这个进程的句柄
      • Process.current()是运行这个java虚拟机的进程句柄
      • ProcessHandle.allProcesses()可以生成对当前进程可见的所有操作系统进程的Stream<ProcessHandle>
  • 相关阅读:
    Java实现 LeetCode 792 自定义字符串排序(暴力)
    Java实现 LeetCode 792 自定义字符串排序(暴力)
    asp.net session对象的持久化
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    小白也能看懂的约瑟夫环问题
  • 原文地址:https://www.cnblogs.com/qinjinyu/p/13461696.html
Copyright © 2011-2022 走看看