Java读书笔记(4)-多线程(二)

2016-1-2

  1. 线程通信

    • 传统的线程通信

      • Object类提供了wait(),notify()和notifyAll三个方法
      • 适用情况:synchronized修饰的同步方法或者synchronized方法
      • wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()或notifyAll方法来唤醒该线程,调用wait方法后本线程会释放对同步监视器的锁定
      • notify():唤醒在此同步监视器上等待的单个线程。如果有多个线程在等待,则随机唤醒其中一个
      • notifyAll():唤醒在此同步监视器上等待的所有线程
    • 使用Condition控制线程通信
      • 适用于使用Lock对象来同步的场景,Condition实例被绑定在一个Lock对象
      • Lock替代了同步方法或同步代码块,Condition替代了同步监视器的功能
      • await(),signal(),signalAll()
      • private final Lock lock=new ReentrantLock();
      • private final Condition cond=lock.newCondition();
      • cond.await()
      • cond.signalAll()
    • 使用阻塞队列(BlockingQueue)控制线程通信
      • add(E e), off(E e), put(E e)
      • remove(), poll(), take()
      • element(), peek()
    • ArrayBlockinQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue, DelayQueue
    • BlockingQueue<Stirng> bq=new ArrayBlockingQueue<>(2);

      bg.put(“Java”)

  2. 线程组(ThreadGroup)和未处理的异常
      • 程序可以直接以组为单位控制线程
      • 线程运行途中不能更改所属线程组
      • ThreadGroup:activeCount(), interrupt(), isDaemon(), setDaemon(), setMaxPriority()
      • ThreadGroup内还定义了一个很有用的方法:void uncaughtException(Thread t,Throwable e), 可以处理线程组内任意线程所抛出的异常
      • 使用catch捕获异常时,异常不会传播给上一级调用者;但是使用异常处理器对异常进行处理后,异常依然会传播给上一级调用者
  3. 线程池
    • 当程序中需要创建大量生存期很短暂的线程时,应该考虑使用线程池。线程池在系统启动时即创建大量空闲的线程
    • Java5实现的线程池
      • 返回一个ExecutorService对象,该对象代表一个线程池:newCachedThreadPool()newFixedThreadPool(int nThreads),newSingleThreadExecutor()
      • new ScheduledThreadPool(int corePoolSize),new SingleThreadScheduledExecutor()
      • 使用线程池来执行线程任务的步骤:
        1. 调用Executors类的静态工厂方法来创建一个ExecutorService对象,该对象代表一个线程池;
        2. 创建Runnable实现类或Callable实现类的实例,作为线程执行任务;
        3. 调用ExecutorService对象的submit()方法来提交Runnable实例或者Callable实例;
        4. 任务执行完毕,最后关闭线程池shutdown()。
    • Java7新增的ForkJoinPool
      • 充分利用多CPU,多核CPU的性能优势
      • 将一个任务拆分成多个“小任务”并行计算,再把多个小任务的结果合并成总的计算结果
      • ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池
      • 创建了ForkJoinPool实例之后,就可以调用ForkJoinPool的submit(ForkJoinTask task)或者invoke(ForkJoinTask task)方法来执行指定任务了。其中ForkJoinTask代表一个可以并行,合并的任务。ForkJoinTask是一个抽象类,它还有两个抽象子类:RecursiveAction和RecursiveTask。其中RecursiveTask代表有返回值的任务,而RecursiveAction代表没有返回值的任务。
  4. 线程相关类
    • ThreadLocal类

      • 代表一个线程局部变量,通过把数据放在ThreadLocal中就可以让每个线程创建一个该变量的副本
      • 在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把对象与线程相关的状态使用ThreadLocal保存
      • ThreadLocal类与线程同步机制面向的问题领域是不同的
      • 如果多个资源之间需要共享资源,以实现线程通信,则使用同步机制;如果仅仅只是隔离多个线程之间的冲突,则使用ThreadLocal
    • 包装线程不安全的集合
      • 可以使用Collections提供的静态方法把这些集合包装成线程安全的集合。

        1. <T> Collection<T> synchronizedCollections(Collection<T> c):返回指定collection对应的线程安全的collection;
        2. static <T> List<T> synchronizedList(List<T> list)
        3. static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
        4. static <T> Set<T> synchronizedSet(Set<T> s)
        5. static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
        6. static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
      • 如果需要把某个集合包装成线程安全的集合,则应该在创建之后立即包装

        HashMap m=Collections.synchronizedMap(new HashMap());

    • 线程安全的集合类
      • java.util.concurrent包
      • 支持高效并发访问的集合接口和实现类
        1. 以Concurrent开头的集合类:支持并发访问的集合
        2. 以CopyOnWrite开头的集合类:适合读取操作远远大于写入操作的场景,如缓存等
时间: 2024-08-08 05:35:19

Java读书笔记(4)-多线程(二)的相关文章

Java学习笔记之多线程二

看到一篇讲线程的故事性文章,觉得很有意思,很佩服作者能这么生动地讲述出来,点击可跳转阅读此文章:<我是一个线程> 继续我的笔记中总结 - - 理解线程安全问题: 下面是书上看到的卖票例子:模拟3个窗口同时在售10张票. 上篇博文笔记总结了多线程创建的两种方式,那我们就分别以这两种实现多线程的方式来解决这个场景. 使用继承于Thread类的方式 上Demo: class SaleTicket extends Thread { int num = 10; // 票数 public SaleTick

Java读书笔记(3)-多线程(一)

2016-1-1 ch16 多线程 线程概述 Java提供了非常优秀的多线程支持,创建,控制,同步,线程池 线程和进程 进程:独立性,动态性,并发性 线程:进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程.线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源.一个线程可以创建和撤销另一个线程,同一个进程中多个线程之间可以并发执行. 多线程的优势 较之多进程编程方便,并发性高,性能好 线程的创建和启动 继承Th

think in java 读书笔记

java中没有单独函数的概念,依赖类的方法. java中优化了向前引用,类可以在调用者之后. java中包的命名方法实际上是网址的倒转. c++中因为存在全局变量和函数所以会存在一个变量名冲突的问题,但是java中不存在全局变量,不同程序设计者通过不同的类将相同名字的变量和方法隔离. static关键字 通常,我们创建类时会指出那个类的对象的外观与行为.除非用new 创建那个类的一个对象,否则实际上并 未得到任何东西.只有执行了new 后,才会正式生成数据存储空间,并可使用相应的方法. 但在两种

Effective Java 读书笔记(2创建和销毁对象)

第一章是引言,所以这里不做笔记,总结一下书中第一章的主要内容是向我们解释了这本书所做的事情:指导Java程序员如何编写出清晰.正确.可用.健壮.灵活和可维护的程序. 2.1考虑用静态工厂方法代替构造器 静态工厂方法与构造器相比有四大优势: (1)静态工厂方法有名称,具有适当名称的静态工厂方法易于使用.易于阅读: (2)不必每次在调用它们的时候都创建一个新的对象: (3)可以返回原返回类型的任何子类型的对象: (4)在创建参数化类型实例的时候,它们使代码变得更加简洁. 同时静态工厂方法也有两大缺点

Effective Java读书笔记(4 类和接口)

4.1 使类和成员的可访问性最小化 要区别设计良好的模块和设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节.设计良好的模块会隐藏所有的实现细节,把它的API与它的实现清晰的隔离开来,然后模块之间只通过API进行通信,一个模块不需要知道其他模块内部的工作情况,这个概念被称为信息隐藏或封装,是软件设计的基本原则之一. 4.2 在公有类中使用访问方法而非公有域 坚持面向对象程序设计思想:如果类可以在它所在的包的外部进行访问,就提供访问方法,以保留将来改

【java读书笔记】——java的异常处理

程序在实际环境的运行过程中,安全成为需要首先考虑的重要因素之一,这也是用户和程序员最关心的问题.同时,Java语言健壮性也体现在了能够及时有效地处理程序中的错误,准确的说是Java的异常处理机制为解决安全问题提交了一份满意的答卷. 先从整体上看一下本文要介绍的内容,然后进行详细的分析: 1.异常的概念 异常又称为例外,是特殊的运行错误对象,对应着Java语言特定的运行错误处理机制. 上面的概念是书本上说的,下面我谈一下自己的看法 其实异常处理机制提供了统一的机制来识别和响应程序错误,异常可以为我

Effective Java读书笔记(3对于所有对象都通用的方法)

3.1 覆盖equals时请遵守通用约定 什么时候应该覆盖Object.equals()方法呢? 如果类具有自己特有的"逻辑相等"概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法. Object.equals()方法具有自反性.对称性.传递性.一致性和与null比较返回false的特点. 实现高质量equals方法的诀窍: (1)使用==操作符检查"参数是否为这个对象的引用".如果是,则返回true,这

Effective C++读书笔记之十二:复制对象时勿忘其每一个成分

Item 12:Copy all parts of an object 如果你声明自己的copying函数,意思就是告诉编译器你并不喜欢缺省显示中的某些行为.而编译器会对"你自己写出copying函数"做出一种复仇的行为:既然你拒绝它们为你写出copying函数,如果你的代码不完全,它们也不会告诉你.结论很明显:如果你为class添加一个成员变量,你必须同时修改copying函数.如果你忘记,编译器不太可能提醒你. 一下提供一种正确的模版: class Date{...}; class

think in java 读书笔记 3 —— 数据报

目录 think in java 读书笔记 1 ——移位 think in java 读书笔记 2 —— 套接字 概要 1. 数据报基本知识 1. 数据报基本知识 之前套接字中例子使用的都是“传输控制协议”(TCP),亦称作“基于数据流的套接字”.根据该协议的设计宗旨,它具有高度的可靠性,而且能保证数据顺利抵达目的地.换言之,它允许重传那些由于各种原因半路“走失”的数据.而且收到字节的顺序与它们发出来时是一样的.当然,这种控制与可靠性需要我们付出一些代价:TCP 具有非常高的开销. 还有另一种协