Concurrency in Java Programming

                                                                                        并发(Concurrency)


1.概念


    并发: 指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果;
    并行: 指在同一时刻,有多条指令在多个处理器上同时执行;

        说明:
            要编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问.
            所有的并发问题都可以归结为如何协调对并发状态的访问.可变状态越少,就越容易确保线程安全性.

    同步:是一种协调两个或更多任务以获得预期结果的机制.同步方式有两种:
            控制同步:当一个任务的开始依赖于另一个任务的结束时,第二个任务不能在第一个任务完成前开始;
            数据访问同步:当两个或更多任务访问共享变量时,在任意时间内,只有一个任务可以访问该共享变量;

        说明:
            '临界区域'是与同步相关的概念.临界区域是一段代码,由于它可以访问共享资源,因此在任何给定时间内,只能被一个任务执行.
            通过'互斥'来保证临界区域在某个时间段内只有一个任务执行.

    不可变对象:不可变对象在其初始化后,不能修改其可视状态(可见域).若想修改一个不可变对象,就必须创建一个新对象.不可变对象是线程安全的.

    原子操作:是一种发生在瞬间的操作.在并发程序中,可以通过一个临界段来实现原子操作,以便对整个操作采用同步机制.

    原子变量:是一种通过原子操作来设置和获取其值的变量.可以使用某种同步机制来实现一个原子变量,或者也可以使用CAS以及无锁方式来实现一个原子变量.

    线程间通信: 第一种方法:共享内存-常用于同一台计算机运行多任务的情况;第二种方法:消息传递-常用于不同计算机运行多任务的情况;

2.Java内存模型


    在共享内存的多处理器体系架构中,每个处理器都拥有自己的缓存,并且定期的与主内存进行协调.
    Java提供了自己的内存模型,并且JVM通过在适当的位置上插入内存栅栏(特殊的指令)来屏蔽在JMM与底层平台内存模型之间的差异.
    
    Java内存模型是通过各种操作来定义的,包括对变量的读写操作,监视器的加锁和释放操作,以及线程的启动和合并操作.
    JMM为程序中所有的操作定义了一个关系,称为'Happens-Before'.要想保证执行操作B的线程看到操作A的结果,那么在A和B之间必须满足Happens-Before关系.
    若两个操作之间缺乏'Happens-Before'关系,那么JVM可以对它们任意的重排序.
    
    当一个变量被多个线程读取并且至少被一个线程写入时,若在读操作和写操作之间没有依据'Happens-Before'来排序,那么就会产生数据竞争问题.
    在正确同步的程序中不存在数据竞争,并会表现出串行一致性,这意味着程序中的所有操作都会按照一种固定的和全局的顺序执行.

        
    1)原子性(Atomicity):
        指一个操作是不可中断的.即使是在多个线程一起执行的时候.一个操作一旦开始,就不会被其它线程干扰.
        例如CPU中的一些指令,属于原子性的,又或者变量直接赋值操作(i=1),也是原子性的,即使有多个线程对赋值,相互也不会干扰.
        而如i++则不是原子性的,因为它实际上i=i+1,若存在多个线程操作i,结果将不可预期.

    2)有序性(Ordering):
        指在单线程环境中,程序是按序依次执行的.
        在多线程环境中,程序的执行可能因为指令重排而出现乱序.

    3)可见性(Visibility):
        指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改.
        可能会影响到可见性的场景:
            1.CPU指令重排: 多条汇编指令执行时,考虑性能因素,会导致执行乱序;
            2.硬件优化: 写吸收,批操作;
            3.编译器优化: JVM层面的指令优化;

    4)指令重排:
        指令重排是指在程序执行过程中,为了性能考虑,编译器和CPU可能会对指令重新排序.
        同步将限制编译器,运行时和硬件对内存操作重排序的方式,从而在实施重排序时不会破坏JMM提供的可见性保证.
        1.CPU指令重排:
            一条汇编指令的执行可以分为很多步骤,分为不同的硬件执行:
                取指IF;
                译码和取寄存器操作数ID;
                执行或有效地址计算EX(ALU逻辑计算单元);
                存储器访问MEM;
                写回WB(寄存器);

            说明:
                既然指令可以被分解为很多步骤,那么多条指令就不一定依次序的执行.
                因为每次只执行一条指令,依次执行效率太低.假设上述每一个步骤都要消耗一个时钟周期,
                那么依次执行的话,一条指令要消耗5个时钟周期,两条指令要消耗10个时钟周期,三条指令消耗15个时钟.
                而若硬件空闲即可执行下一步,类似于工厂中的流水线,一条指令要消耗5个时钟周期,两条指令只要6个时钟周期,
                因为是错位流水线,三条指令消耗7个时钟周期.

                指令重排只可能发生在毫无关系的指令之间,若指令之间存在依赖关系,则不会重排.
                例如: 指令1: a=1; 指令2: b=a-1; 则指令1,2不会发生重排.

        2.编译器优化重排:
            主要指JVM层面.
        
    5)Happens-Before规则:
        内存栅栏(Memory Barrier)就是从本地或工作内存到主存之间的拷贝动作.仅当写操作线程先跨越内存栅栏而读线程后跨越内存栅栏的情况下,
        写操作线程所做的变更才对其他线程可见.关键字synchronized和volatile都强制规定了所有的变更必须全局可见,该特性有助于跨越内存边界动作的发生.
        在程序运行过程中,所有的变更会先在寄存器或本地缓存中完成,然后才会被拷贝到主存以跨越内存栅栏.这种跨越序列或顺序称为'happens-before'.
        写操作必须要'happens-before'读操作,即写线程需要在所有读线程跨越内存栅栏之前完成自己的跨越动作,其所做的变更才能对其他线程可见.
        
        若只靠synchronized和volatile来保证程序执行过程中的原子性,有序性,可见性,那么代码将会变得异常繁琐.
        JMM提供了Happens-Before规则来约束数据之间是否存在竞争,线程环境是否安全.具体如下:
            1.程序顺序规则:
                若程序中操作A在操作B之前,那么在线程中A操作将在B操作之前执行.
                即:单个线程内保证语义的串行性; a=1; b=a+1;

            2.监视器锁规则:
                在监视器锁上的解锁操作必须在同一个监视器锁上的加锁操作之前执行.
                即:解锁(unlock)必然发生在加锁(lock)前.

            3.volatile变量规则:
                对volatile变量的写入操作必须在对该变量的读操作之前执行.
                即:volatile变量的写,先发生于读,这保证了volatile变量的可见性.

            4.线程启动规则:
                在线程上对Thread.start()的调用必须在该线程中执行任何操作之前执行.
                即:线程的start()方法先于它的每一个动作.
                
            5.线程中断规则:
                当一个线程在另一个线程上调用interrupt()时,必须在被中断线程检测到interrupt()调用前执行.
                即:线程的中断(interrupt())先于被中断线程的代码.

            6.线程结束规则:
                线程中的任何操作都必须在其他线程检测到该线程已经结束前执行,或从Thread.join()中成功返回,或在调用Thread.isAlive()时返回false.
                即:线程的所有操作先于线程的终结(Thread.join()).

            7.终结器规则:
                对象的构造函数必须在启动该对象的终结器之前执行完成.
                即:对象的构造函数执行结束先于对象的finalize()方法.

            8.传递性:
                若操作A在操作B之前执行,并且操作B在操作C之前执行,那么操作A必须在操作C之前执行.
                即:A先于B,B先于C,那么A必然先于C.

        在类库中提供的其他'Happens-Before'排序规则:
            1.将一个元素放入一个线程安全容器的操作将在另一个线程从该容器中获取这个元素的操作前执行.
            2.在CountDownLatch上的倒数操作将在线程从闭锁上的await()方法中返回之前执行.
            3.释放Semaphore许可的操作将在从该Semaphore上获取一个许可之前执行.
            4.Future表示的任务的所有操作将在从Future.get()中返回之前执行.
            5.向Executor提交一个Runnable或Callable的操作将在任务开始执行之前执行.
            6.一个线程到达CyclicBarrier或Exchanger的操作将在其他到达该栅栏或交换点的线程被释放前执行.
              若CyclicBarrier使用一个栅栏操作,那么到达栅栏的操作将在栅栏操作之前执行,而栅栏操作又会在线程从栅栏中释放之前执行.

3.线程


    1)概念:
          a.进程:
            进程就是应用程序的运行实例,每个进程都有自己私有的虚拟地址空间.每个进程都有一个主线程,但可以建立另外的线程.
            进程中的线程是并行执行的,每个线程占用CPU的时间由系统来划分.

          b.线程:
            线程是进程中的一个执行流程,也称执行情景(线程是进程的执行单元).一个进程可由多个线程组成.
            可把线程看成是操作系统分配CPU时间的基本实体.系统不停地在各个线程间切换,为每一个线程分配一个CPU时间片,
            某个线程只有在分配的时间片内才有对CPU的控制权.在单核计算机中,同一时刻只有一个线程在运行.
            由于系统为每个线程划分的时间片很短,所以看上去好像是多个线程在同时运行;
            在多核计算机中,同一时刻可有多个线程在运行,实现了真正意义的多线程.
            说明: 进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程的全局变量和资源.
                  这一方面为编程带来了方便,但另一方面也容易造成冲突.


    2)分类:
          a.用户线程:
              默认创建的线程都是用户线程;
              由用户线程创建的线程默认下仍然是前台线程;由守护线程创建的线程默认情况下仍然是守护线程;

          b.守护线程('daemon thread'):
            在线程启动前(start()方法执行前),通过调用thread.setDaemon(true)将线程转换为守护线程;
            守护线程服务于用户线程. 守护线程要等到所有用户线程都结束以后才能结束;
            守护线程的唯一用途是为用户线程提供服务.守护线程不应该去访问固有资源,如文件,数据库;
            

    3)优先级:
          每一个线程都有一个优先级.默认情况,一个线程继承它的父线程的优先级.
          可以使用setPriority(int newPriority)方法提高或降低任何一个线程的优先级.
          可将优先级设置为在MIN_PRIORITY(在Thread类中定义为1)与MAX_PRIORITY(在Thread类中定义为10)之间的任何值.
          NORM_PRIORITY被定义为5. 线程调度器在选择新线程时,会首先选择优先级较高的线程.优先级是高度依赖系统的.
          JVM会将线程优先级映射到宿主机平台的优先级.


    4)Thread类和Runnable接口:
        a.Thread类:
            签名:public class Thread extends Object implements Runnable { }
            线程是程序中的'执行线程'.JVM允许程序并发地运行多个执行线程.每个线程都有一个标识名,多个线程可以同名.
            若线程创建时没有指定标识名,就会为其生成一个新名称.

            Thread.currentThread()代表当前线程对象,而this代表当前对象,程序运行时当前线程对象并不一定是当前对象.
            线程优先级(Thread Priorities): Thread类中有三个int类型静态域用来表示线程的优先级.
            分别是MAX_PRIORITY(最高优先级), MIN_PRIORITY(最低优先级), NORM_PRIORITY(默认优先级).

            操作系统完全能够看得到虚拟机内的每一个线程,同时虚拟机的线程和操作系统的线程是一一对应的.Java的线程调度是由操作系统底层线程决定.

            守护线程的作用是在程序的运行期间在后台提供一种'常规'服务,但它并不属于程序的一个基本部分.因此,一旦所有非守护线程完成,程序也会中止运行.
            反之,假如有任何非守护线程仍在运行,比如还有一个正在运行main()的线程,则程序的运行不会中止.

            通过调用isDaemon()方法,可判断一个线程是不是守护线程,而且能用setDaemon(true)方法设置某个线程为守护线程.
            若是一个守护线程,那么它创建的任何线程也自动是守护线程.
            
            线程优先级:
                所有处于就绪状态的线程根据优先级存放在可运行池中,优先级低的线程获得较少的运行机会,
                优先级高的线程获得较多的运行机会.Thread.setPriority(int)和Thread.getPriority()方法用来设置和读取优先级.
                优先级用整数表示,取值范围为1~10.Thread类有三个静态常量:
                    MAX_PRIORITY=10 //最高优先级
                    MIN_PRIORITY=1  //最低优先级
                    NORM_PRIORITY=5 //分配给线程的默认优先级
                说明: 若希望程序能够在各种操作系统中运行良好,应该确保在设置线程优先级时,只使用以上的三个优先级.
                      以此来保证在不同的操作系统中,对相同优先级的线程采用相同的调度方式.

            构造:
                Thread()  //创建Thread对象
                Thread(String name)  //创建Thread对象,指定name做为线程名
                
                Thread(Runnable target) //创建Thread对象,将target做为运行对象
                Thread(Runnable target, String name)  //创建Thread对象,将target做为运行对象,name做为线程名
                
                Thread(ThreadGroup group, String name)  //创建Thread对象,做为线程组group的一员
                Thread(ThreadGroup group, Runnable target)  //创建Thread对象,做为线程组group的一员
                Thread(ThreadGroup group, Runnable target, String name)  //创建Thread对象,做为线程组group的一员
                Thread(ThreadGroup group, Runnable target, String name, long stackSize)  //创建Thread对象,做为线程组group的一员
                
            静态方法:
                static int activeCount()  //返回当前线程的线程组中活动线程的数目
                static Thread currentThread()  //返回对当前正在执行的线程对象的引用
                static boolean interrupted()  //判断当前线程是否已经中断
                static int enumerate(Thread[] tarray)  //将当前线程的线程组及其子组中的每一个活动线程复制到指定的数组中
                static boolean holdsLock(Object obj)  //只有当前线程在指定的对象上保持监视器锁时,返回true
                static Map<Thread,StackTraceElement[]> getAllStackTraces() //返回所有活动线程的堆栈跟踪的一个映射
                static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
                                                        //返回线程由于未捕获到异常而突然终止时调用的默认处理程序
                static void dumpStack()     //将当前线程的堆栈跟踪打印至标准错误流
                static void sleep(long millis)  //线程休眠:在指定毫秒数内让当前正在执行的线程休眠
                static void sleep(long millis, int nanos)  //线程休眠:在指定毫秒数加指定纳秒数内让当前正在执行的线程休眠(暂停执行)
                static void yield()  //线程让步:暂停当前正在执行的线程对象,并执行其他线程
                static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
                                    //设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序

            实例方法:
                long getId()  //返回该线程的标识符
                String getName()  //返回该线程的名称
                int getPriority()  //返回线程的优先级
                Thread.State getState()  //返回该线程的状态
                boolean isAlive()  //测试线程是否处于活动状态
                boolean isDaemon()  //测试线程是否是守护线程
                boolean isInterrupted()  //测试线程是否已经中断
                void start()  //启动线程
                void run()  //若该线程是使用独立的Runnable运行对象构造的,则调用该Runnable对象的run方法;否则,该方法不执行任何操作并返回
                void interrupt()  //中断线程
                void checkAccess()  //判定当前运行的线程是否有权修改该线程
                void join()  //等待该线程结束
                void join(long millis)  //等待该线程终止的时间最长为millis毫秒
                void setName(String name)  //设置线程名称为name
                void setDaemon(boolean flag)  //设置守护线程(flag=true) 或 设置用户线程(flag=false)
                void setPriority(int new Priority)  //设置线程的优先级
                

        b.Runnable接口:
            签名: public interface Runnable { }
            函数式接口(@FunctionalInterface).代表可执行的线程任务.
            主要方法:
                void run()  //表示线程要运行的代码,没有返回值


    5)Callable接口和Future接口:
        支持异步运算.

        a.Callable接口:
            签名: public interface Callable<V> { }
            函数式接口(@FunctionalInterface),与Runnable接口类似,都指定了线程所要执行的操作.
            区别是Callable接口是在call()方法中指定线程所要执行的操作,并且该方法有泛型的返回值'<V>'.
            主要方法:
                V call(): 线程要运行的代码,可以有返回值.


        b.Future接口:
            签名: public interface Future<V> { }
            能够保存异步计算的结果.
            主要方法:
                V get()  //返回异步计算的结果.若运算结果没有出来,当前线程就会被阻塞,直到获得运算结果
                V get(long timeout, TimeUnit unit)  //为阻塞设定时间,若超过参数设置的限定时间,还未获得运算结果,会抛出TimeoutException异常
                 boolean cancel(boolean mayInterrupt)
                                     //取消该运算.若运算未开始,就立即取消.若运算已经开始,且参数为true,会取消该运算.
                                     //若运算已经开始,且参数为false,不会取消该运算,让其继续执行.
                 boolean isCancelled() //若在任务正常完成前将其取消,则返回true
                 boolean isDone()  //判断运算是否已经完成,若已经完成,则返回true

             1.Future接口的子接口:
                 RunnableFuture: 继承Runnable接口和Future接口. 可作为Runnable的Future.执行run方法可以完成Future并允许访问其结果.
                 ScheduledFuture: 继承Future接口和Delayed接口. 延迟的,结果可接受的任务,可将其取消.
                 RunnableScheduledFuture: 继承RunnableFuture接口和ScheduledFuture接口. 可作为Runnable的ScheduledFuture.
                 
             2.Future接口的实现类:
                 a.Future的基础实现: FutureTask
                     签名: public class FutureTask<V> extends Object implements RunnableFuture<V> { }
                     一个适配器,同时实现了Runnable接口和Future接口,又会关联一个Callable实例.
                     实际上把Callable接口转换为Runnable接口. FutureTask的实例可以作为Thread类的构造参数.
                     
                     FutureTask表示一个计算的过程,这个过程可能已经计算完成,也可能正在进行.
                    若有结果可用,那么FutureTask.get()将立即返回结果,否则它会一直阻塞,直到结果计算出来再将其返回.

                b.可完成的Future: CompletableFuture
                     签名: public class CompletableFuture<T> extends Object implements Future<T>, CompletionStage<T>
                    扩展了Future机制,以一种异步方式生成任务的结果.可以指定任务在结果生成后执行,这样就可以控制任务的执行顺序.
                 
                 c.Fork/Join框架的Future实现:
                    ForkJoinTask:
                    CountedCompleter:
                    RecursiveAction:
                    RecursiveTask:


    6)生命周期和状态转换:
    
          a.线程的生命周期:

                              Waiting(等待)     Timed Waiting(计时等待)
                                       ||                ||
                         New(创建) --> Runnable(可运行) --> Terminated(被终止)
                                           ||
                                       Blocked(被阻塞)

        b.线程的六种状态:
            New(新创建), Runnable(可运行), Blocked(被阻塞), Waiting(等待), Timed Waiting(计时等待), Terminated(被终止);
            线程的所有可能状态都在Thread.State枚举类中保存.

          c.创建线程的三种方法:
              1.继承Thread类,实现run()方法:
                  public class MyThread extends Thread {
                      public void run(){ ... }
                  }

                  Thread t1 = new MyThread();
                  t1.start(); //启动线程
              说明:使用继承Thread的方法来创建线程类时,多个线程间无法共享线程类的实例变量


              2.实现Runnable接口,实现run()方法:
                    public class MyRunnable implements Runnable {
                      public void run(){ ... }
                    }

                    Runnable r1 = new MyRunnable();
                    Thread t = new Thread(r1);
                    t.start(); //启动线程
                说明:Runnable实现类的run()方法作为线程执行体.实例线程对象是Thread实例.
                     从Java8开始,Runnable接口被@FunctionInterafce修饰,即Runnable接口成为函数式接口,
                     可以使用Lambda表达式创建Runnable接口的对象.

      
              3.实现Callable接口,实现call()方法:
                    public class MyCallable implements Callable<Object> {
                      public Obejct call() throws Exception {
                            return new Object();
                      }
                    }
                说明:
                        call()方法可以有返回值,call()方法可以声明抛出异常.
                        要使用Callable来表示无返回值的任务,可使用Callable<void>.
                        Future接口表示一个任务的生命周期,并提供相应的方法来判断是否已经完成或取消,
                        以及获取任务的结果和取消任务等.Future能保存运算结果.
                    在Future规范中包含的隐含意义是: 任务的生命周期只能前进,不能后退.
                    FutureTask类实现了RunnableFuture接口(Future接口,Runnable接口的子接口).
                    从Java8开始,Callable接口也成为了函数式接口,可以使用Lambda表达式来创建实例.


              4.特殊形式:
                  a.使用ThreadFactory接口实现:
                      例子:
                          Thread t1 = Executors.defaultThreadFactory().newThread(() -> { //返回线程前将已创建线程的上下文设置为已知的值
                            System.out.println(new Date());
                        });
                        t1.start(); //启动线程

                  b.匿名内部类形式实现:
                    例子:
                        Thread t = new Thread(new Runnable() {
                            public void run() { ... }
                        });
                        t.start(); //线程启动

                c.Lambda表达式形式实现:
                
        d.线程状态的转换:

        
    7)线程组(ThreadGroup):
        线程组是一个可以统一管理的线程集合.此外,线程组也可以包含其他线程组.线程组构成一棵树,在树中除了初始线程组外,
        每个线程组都有一个父线程组.允许线程访问有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组
        或其他任何线程组的信息.
        ThreadGroup实现了Thread.UncaughtExceptionHandler接口.
            构造: ThreadGroup(String name)
                  ThreadGroup(ThreadGroup parent,String name)
        注意:因为有了线程池,通常不建议使用线程组.

4.线程同步


    同步发生的场景:
        若正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个线程写过的变量,那么必须使用同步.
        并且,读写线程都必须用相同的监视器锁同步.
        每个访问临界共享资源的方法都必须被同步,否则他们就无法正确工作.

    临界区:
        多个线程可能同时访问方法内部的部分代码,则这段代码被称为临界区(critical section).
        
    1)使用隐式锁
        隐式锁(Implicit Lock),Java内建同步机制,又称为'synchronized'锁.
        隐式锁(synchronized关键字)配合Object对象的wait(),notify(),notifyAll()方法实现线程间通信.
        
        条件对象-等待/通知的使用规则:
            只有同时满足以下两个条件时,才能用单一的notify()而不是notifyAll():
            1.所有等待线程的类型都相同; 只有一个条件谓词与条件对象相关,并且每个线程在从wait()返回后将执行相同的操作.
            2.单进单出; 在条件变量上的每次通知,最多只能唤醒一个线程来执行.
            
        a.同步方法:
            使用关键字'synchronized'修饰.同步方法锁的是当前对象(this).
            每一个Java对象有一个内部锁和内部条件.线程可以通过调用同步方法获得锁.
            一个方法用'synchronized'关键字声明,那么它的表现就像是一个监视器方法.
            通过调用wait()/notifyAll()/notify()来访问条件对象.
            静态方法也可用'synchronized'关键字修饰,此时锁的是类本身(Class对象).
            形式:
                public synchronized void sum() {
                    ...
                }
          
        b.同步代码块:
            使用关键字'synchronized'将可能产生并发读写的代码置于其中.同步代码块锁的是任意对象.
            若某个对象被同步代码块或同步方法锁定,那么其他使用该对象的代码必须等待,直到该对象的锁被释放.

            'synchronized'块必须给定一个在其上进行同步的对象,并且最合理的方式是,使用其方法正在被调用的当前对象:synchronized(this).
            此时,若获得了synchronized代码块上的锁,那么该对象其他的synchronized方法和临界区就不能被调用.
            因此,若在this上同步,临界区的效果就会直接缩小在同步范围内.
            
            形式:
                synchronized(obj) {
                    ...
                }

          
    2)使用显式锁
        a.显式锁(Explicit Lock):
            锁机制既可以保证可见性,又可以保证原子性.
            显式锁Lock配合Condition对象的await(),signal(),signalAll()方法实现线程间通信.

            接口: Lock
            实现类: ReentrantLock(可重入锁)
            使用场景:

            形式一:
                Lock lock = new ReentrantLock();
                lock.lock(); //获得锁
                try{
                    ... //需要同步的代码
                }finally{
                  lock.unlock(); //释放锁
                }

            形式二:
                

            接口: ReadWriteLock
            实现类: ReentrantReadWriteLock(读写分离锁)
            使用场景: 若很多线程从一个数据结构读取数据而很少线程修改其中数据的情况; 特点:读锁会完全阻塞写锁.

            形式:
                ReadWriteLock lock = new ReentrantReadWriteLock();

                public void method1(){ //对所有的获取方法加读锁
                      lock.readLock().lock();
                      try{
                          ...
                      }finally{
                        lock.readLock().unlock();
                      }
                }

                public void method2(){ //对所有的修改方法加写锁
                      lock.writeLock().lock();
                      try{
                        ...
                      }finally{
                        lock.writeLock().unlock();
                      }
                }
                
            实现类: StampedLock(控制锁)
            使用场景: Java8新增StampedLock类,在大多数场景中可以替代传统的ReentrantReadWriteLock.是读写锁的改进.
                      为读写操作提供了三种锁模式: Writing(写), Reading(读), Optimistic Reading(乐观读).
                      特点: 读锁不会阻塞写锁.
            主要方法:
                    readLock(): 获取读锁,阻塞,不响应中断;
                    readLockInterruptibly(): 获取读锁,阻塞,响应中断;
                    tryReadLock(): 立即获取读锁;
                    tryReadLock(long time, TimeUnit unit): 限时获取读锁,响应中断;

            形式:

        b.锁超时:

        c.死锁(Deadlock):
            有一组进程或线程,其中一个无限等待被该组进程或线程中另一个进程或线程所占有的资源,就会产生无限期等待状态,称为死锁.
            对锁的循环依赖造成死锁.
            发生死锁必须满足的四个条件:
                1.互斥条件.任务使用的资源中至少有一个是不能共享的;
                2.至少有一个任务它必须持有一个资源且正在等待获取一个当前被别的任务持有的资源;
                3.资源不能被任务抢占,任务必须把资源释放当做普通事件;
                4.必须有循环等待,这时,一个任务等待其他任务所持有的资源,后者又在等待另一个任务所持有的资源,这样一直下去,
                  直到有一个任务在等待第一个任务所持有的资源,使得大家都被锁住;

            说明:要发生死锁的话,所有这些条件必须全部满足.所以要预防死锁发生,只需要破坏其中的一个条件即可.
                预防死锁最简单的方法是破坏第4个条件.当然也可以通过破坏其他条件来预防死锁.

            活锁(Livelock):对于某个操作的持续尝试,却持续失败.

        d.条件对象(Condition):
                线程进入临界区,却发现在某一条件满足后它才能执行.要使用一个条件对象来管理那些已经获得了一个
                锁但是却不能做有用工作的线程. 一个锁对象可以有一个或多个相关的条件对象.
            方法:
                void await():将当前线程放到条件的等待集中(使当前线程等待),直到其他线程调用该Condition的signal(),signalAll();
                void signal():从该条件的等待集中随机选择一个线程,解除其阻塞状态(唤醒在此Lock对象上等待的单个线程);
                void signalAll():解除该条件的等待集中的所有线程的阻塞状态(唤醒在此Lock对象上等待的所有线程);

        e.队列同步器(AbstractQueuedSynchronizer,AQS):
            用来构建锁或其他同步组件的基础框架.
            ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,SynchronousQueue,FutureTask都是基于AQS构建的.

           f.LockSupport:
               并发工具控制机制的基础.
               用来创建锁和其他同步类的基本线程阻塞原语.
               park()方法阻塞线程,unpark()方法解除阻塞.


    3)volatile域与final域:
        a.volatile域:
            原理: volatile用于确保将变量的更新操作通知到其他线程.当把变量声明为volatile类型后,
                  编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序.
                  volatile变量不会被缓存在寄存器或对其他处理器不可见的地方,因此在读取volatile类型的变量时总会
                  返回最新写入的值.

            使用场景:
                仅当volatile变量能简化代码的实现以及对同步策略的验证时,才应该使用.
                volatile只能保证可见性,不能保证原子性.
            
            使用方式:
                确保它们自身状态的可见性; 确保它们所引用对象的状态的可见性;标识一些重要的程序生命周期事件的发生.

        b.final域:
            '不可变对象一定是线程安全的'. 在Java内存模型中,final域有着特殊的语义: final域能确保初始化过程的安全性,
            从而可以不受限制的访问不可变对象,并在共享这些对象时无需同步. final修饰的域可保证域的可见性.
            不可变对象能极大的降低并发编程的复杂性.可以任意共享而无须使用加锁或保护性复制等机制.


    4)原子操作:
        java.util.concurrent.atomic包中提供了使用高效机器级指令的类来保证其他操作的原子性.
        原子操作是不能被线程调度机制中断的操作.一旦操作开始,那么它一定可以在可能发生的'上下文切换'之前(切换到其他线程执行)执行完毕.

        a.CAS(CompareAndSwap,即比较并交换指令):
            一个原始操作.它比较一个内存位置的值并且只有相等时修改这个内存位置的值为新值,
            保证了新的值总是基于最新的信息计算得来,若有其他线程在这期间修改了这个值则CAS失败.
            CAS返回是否成功或内存位置原来的值用于判断CAS是否成功.
            JVM中的CAS操作是利用处理器提供的CMPXCHG指令实现的.
            特点:
                竞争不大的情况下系统开销小;
                循环时间长开销大;
                ABA问题;
                只能保证一个共享变量的原子操作;

        b.原子类(java.util.concurrent.atomic):
            基本类: AtomicInteger  AtomicLong  AtomicBoolean
            引用类型: AtomicReference  AtomicStampedReference  AtomicMarkableReference
            数组类型: AtomicIntegerArray  AtomicLongArray  AtomicReferenceArray
            属性原子修改器(volatile): AtomicIntegerFieldUpdater  AtomicLongFieldUpdater  AtomicReferenceFieldUpdater
            其他: LongAdder  DoubleAdder


    5)阻塞队列(Blocking Queue):
        阻塞队列导致线程阻塞,作为线程同步的工具,在协调多个线程之间的合作时,是一个有用的工具.
        特点: 当生产者线程试图向阻塞队列中放入元素时,若该队列已满,则该线程被阻塞;
              当消费者线程试图从阻塞队列中取出元素时,若该队列已空,则该线程被阻塞;

            程序的两个线程通过交替向阻塞队列中放入元素,取出元素,即可很好的控制线程的通信.
            阻塞队列提供如下两个支持阻塞的方法:
                put(E e): 试图把元素E放入阻塞队列中,若该队列的元素已满,则阻塞该线程;
                take(): 试图从阻塞队列的头部取出元素,若该队列的元素已空,则阻塞该线程;

        java.util.concurrent包提供了一些阻塞队列.比如:

            LinkedBlockingQueue(无界链表阻塞队列):

            LinkedBlockingDeque(无界链表双向阻塞队列):

            LinkedTransferQueue(无界链表传输队列):

            ArrayBlockingQueue(数组有界阻塞队列):

            PriorityBlockingQueue(无界优先级阻塞队列):

            DelayQueue(无界延时队列):

            SynchronousQueue(同步队列):
                同步队列是一种将生产者与消费者线程配对的机制.
                场景: 在没有显式同步的情况下,当两个线程准备好将一个对象从一个线程传递到另一个时;
                功能: 允许一个线程把对象交给另一个线程;
                例子:


    6)同步包装器:
        通过同步包装器,得到的是线程安全的集合.
        Collections工具类提供如下静态方法,以获得线程安全的集合类:
            <T> Collection<T> synchronizedCollection(Collection<T> c): 返回指定collection对应的线程安全的collection.
            <T> List<T> synchronizedList(List<T> list): 返回指定List对象对应的线程安全的List对象.
            <T> Set<T> synchronizedSet(Set<T> s): 返回指定Set对象对应的线程安全的Set对象.
            <K,V> Map<K,V> synchronizedMap(Map<K,V> m): 返回指定Map对象对应的线程安全的Map对象.

        例子:
            List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E>());
            Map<K, V> synchHashMap = Collections.synchronizedMap(new HashMap<K, V>());
            //若需要在另一个线程可能进行修改时要对集合进行迭代,需要使用'客户端'锁定.必须同步
            synchronized(synchHashMap) {
                Iterator<K> ite = synchHashMap.keySet().iterator();
                while(ite.hasNext()) {
                    K k = ite.next();
                    // ...
                }
            }

            synchronized() {
                for(K k: synchHashMap.keySet()) {
                    k...
                }
            }


    7)并发容器(non-block):
        a.支持并发访问的集合(使用分段锁技术实现):
            ConcurrentHashMap:
                默认支持16个线程并发写入.第17个并发的线程需要等待,也可以通过构造参数来支持更多的并发写入线程.
                
                原理: 基于分段锁(Lock Striping)实现.分段锁,一种粒度更细的加锁机制;
                        任意数量的读取线程可以并发地访问Map,执行读取操作的线程和执行写入操作的线程可以并发的访问Map,
                        并且一定数量的写入线程可以并发地修改Map;
                        在ConcurrentHashMap中没有实现对Map加锁以提供独占访问;
                        锁分段的劣势:要获取多个锁来实现独占访问将更加困难且开销更高;
                        
                        在ConcurrentHashMap的实现中使用了一个包含16个锁的数组,每个锁保护所有散列桶的1/16,
                        其中第N个散列桶由第(N mod 16)个锁来保护.
                        假设散列函数具有合理的分布性,并且关键字能够实现均匀分布,那么这大约能把对于锁的请求减少到原来的1/16.
                        正是这项技术使得ConcurrentHashMap能够支持多达16个并发的写入器.

            ConcurrentSkipListMap:

            ConcurrentSkipListSet:

            ConcurrentLinkedQueue:

            ConcurrentLinkedDeque:


        b.支持并发读写的集合(使用写时复制技术实现):
            写时复制技术: 复制底层数组的方式来实现写操作.
            适用于读操作远大于写操作的场景中,比如缓存.

                原理: 写入时复制(Copy-On-Write)容器,在每次修改时都会创建并重新发布一个新的容器副本,从而实现可变性.
                        "写入时复制"容器的迭代器保留一个指向底层基础数组的引用,这个数组当前位于迭代器的起始位置,
                        由于它不会被修改,因此在对其进行同步时只需确保数组内容的可见性.
                        因此,多个线程可以同时对这个容器进行迭代,而不会彼此干扰或与修改容器的线程相互干扰.
                  
                使用场景: 每当修改容器时都会复制底层数组,这需要一定的开销,特别是当容器的规模较大时.
                            仅当迭代操作远远多于修改操作时,才应该使用'写入时复制'容器.

            CopyOnWriteArrayList:

            CopyOnWriteArraySet:


    8)线程同步工具:
         a.CountDownLatch(闭锁):
             它被用来同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成.
             可以向CountDownLatch对象设置一个初始计数值,任何在这个对象上调用wait()的方法都将阻塞,直至这个计数值为零.
             其他任务在结束其工作时,可以在该对象上调用countDown()方法来减少计数值,调用countDown()方法不会被阻塞.
            
            场景: 当一个或多个线程需要等待直到指定数目的事件发生;
            功能: 允许线程集等待直到计数器减为0; 用于等待事件.
            例子:
                final CountDownLatch latch = new CountDownLatch(1); //在构造器中设定计数值

                Runnable onTimeTask = new Runnable() {
                    final Random random = new Random();
            
                    public void run() {
                        try {
                            TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));
                            System.out.print("Task Complated");
                            latch.countDown(); //计数减1
                            System.out.println(" -1 ");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };

                Runnable waitTask = new Runnable() {
                    public void run() {
                        try {
                            System.out.println("waitting other task start");
                            latch.await(); //阻塞等待
                            System.out.println("waitting other task closed");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };

                ExecutorService pool = Executors.newCachedThreadPool();
                pool.execute(waitTask);
                pool.execute(onTimeTask);
                pool.shutdown();

                   
        b.CyclicBarrier(关卡):
            若想创建一组任务,它们并行的执行工作,然后在进行下一个步骤前等待,直至所有任务都完成.
            它使得所有的并行任务都将在栅栏处列队,因此可以一致的向前移动.类似CountDownLatch,但CountDownLatch是只触发一次的事件,
            而CyclicBarrier则可以多次重用.

            场景: 当大量的线程需要在它们的结果可用前完成时;
            功能: 允许线程集等待直至其中预定数目的线程到达一个公共障碍(barrier),然后可以选择执行一个处理障碍的动作.
                  类似闭锁,能阻塞一组线程直到某个事件发生. 用于等待其他线程.
            例子:
                final CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
                    public void run() {
                        System.out.println("等待的任务全到达");
                    }
                });

                Runnable r0 = new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep((long) (Math.random() * 10000));
                            System.out.println("任务" + Thread.currentThread().getName() + "到达");
                            barrier.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (BrokenBarrierException e) {
                            e.printStackTrace();
                        }
                    }
                };

                ExecutorService pool = Executors.newCachedThreadPool();
                for (int i = 0; i < 5; i++) {
                    pool.execute(r0);
                }
                pool.shutdown();
                

        c.Semaphore(信号量):
            计数信号量允许n个任务同时访问一项资源.还可以将信号量看作是在向外分发使用资源的'许可证',尽管实际上没有使用任何许可证对象.

            场景: 限制访问资源的线程总数.若许可数是1,常常阻塞线程直到另一个线程给出许可为止;
            功能: 允许线程集等待直到被允许继续运行为止.用来控制同时访问某个特定资源的操作数量,
                  或同时执行某个指定操作的数量. 用来实现资源池,或为容器设置边界.
                  Semaphore中管理着一组虚拟的许可(permit),许可的初始数量可通过构造函数来指定.
                  在执行操作时可以首先获得许可(有许可的情况下),并在使用后释放许可.若没有许可,
                  那么acquire()将阻塞直到有许可(或直到被中断或操作超时).release()方法将返回一个
                  许可给信号量.

            例子:
                final Semaphore semaphore = new Semaphore(5);
        
                Runnable r0 = new Runnable() { //访问资源的任务
                    public void run() {
                        try {
                            Thread.sleep(300L);
                            semaphore.acquire(); // 任务-获得许可证
                            System.out.println(Thread.currentThread().getName() + "获得访问资源的许可-访问资源");
                            Thread.sleep(1000L);
                            semaphore.release(); // 释放资源
                            System.out.println(Thread.currentThread().getName() + "释放资源-释放许可证-访问结束");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };

                ExecutorService pool = Executors.newCachedThreadPool();
                for (int i = 0; i < 20; i++) {
                    pool.execute(r0);
                }
                pool.shutdown();
                

        d.Exchanger(交换器):
            Exchanger是在两个任务之间交换对象的栅栏.当这些任务进入栅栏时,它们各自拥有一个对象,当它们离开时,他们都拥有之前由对象持有的对象.

            场景: 当两个线程工作在同一数据结构的两个实例上时,一个向实例添加数据而另一个从实例清除数据;
            功能: 允许两个线程在要交换的对象准备好时交换对象;
                  Exchanger是一种双方栅栏(Two Party Barrier),各方在栅栏位置上交换数据.当双方执行不对称的操作时,
                  Exchanger会非常有用,例如当一个线程向缓冲区写入数据,而另一个线程从缓冲区中读取数据.
                  这些线程可以使用Exchanger来汇合,并将满的缓冲区与空的缓冲区交换.当两个线程通过Exchanger交换对象时,
                  这种交换就把这两个对象安全的发布给另一方.
                  
            例子:
                final Exchanger<String> exchanger = new Exchanger<>();
                Runnable r0 = new Runnable() {
                    String person = "河南人";
                    
                    public void run() {
                        try {
                            System.out.println(Thread.currentThread().getName() + "-r0-" +exchanger.exchange(person));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };

                Runnable r1 = new Runnable() {
                    String person = "云南人";
                
                    public void run() {
                        try {
                            System.out.println(Thread.currentThread().getName() + "-r1-" +exchanger.exchange(person));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                
                ExecutorService pool = Executors.newCachedThreadPool();
                pool.execute(r0);
                pool.execute(r1);    
                pool.shutdown();


        e.Phaser(分段器):
            运行分为多阶段的任务.提供分段器,将任务划分为多个阶段执行.任务可以要求Phaser类等待直到所有其他参与方完成该阶段.
            Phaser类是一种同步机制,用于控制以并发方式划分为多个阶段的算法的执行.若处理过程已有明确定义的步骤,
            那么必须在开始第二个步骤前完成第一步的工作,以此类推,并且可以使用Phaser类实现该过程的并发版本.
            Phaser类的主要特征:
                1.分段器(phaser)必须知道要控制的任务数.Java称为参与者的注册机制.参与者可以随时在分段器中注册;
                2.任务完成一个阶段后必须通知分段器.在所有参与者都完成该阶段前,分段器将使该任务处于休眠状态;
                3.在内部,分段器保存了一个整数值,该值存储分段器已经进行的阶段变更数目;
                4.参与者可以随时脱离分段器的控制.Java将这一过程称为参与者的注销;
                5.当分段器做出阶段变更时,可以执行定制的代码;
                6.控制分段器的终止.若一个分段器终止了,就不再接受新的参与者,也不会进行任务间的同步;
                7.通过一些方法获得分段器的参与者数目及其状态;
                
            场景:
            功能:类似于循环障碍,有一个可变的计数;
            例子:
                final Phaser phaser = new Phaser(3);
                Runnable r1 = new Runnable() {
                    public void run() {
                        System.out.println(Thread.currentThread() + "-> stage1");
                        phaser.arriveAndAwaitAdvance(); //到达屏障并等待
                        System.out.println(Thread.currentThread() + "-> stage2");
                        phaser.arriveAndAwaitAdvance();
                        System.out.println(Thread.currentThread() + "-> stage3");
                    }
                };
        
                Runnable r2 = new Runnable() {
                    public void run() {
                        System.out.println(Thread.currentThread() + "-> stage1");
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        phaser.arriveAndAwaitAdvance();
                        System.out.println(Thread.currentThread() + "-> stage2");
                        try {
                            Thread.sleep(600);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        phaser.arriveAndAwaitAdvance();
                        System.out.println(Thread.currentThread() + "-> stage3");
                    }
                };
        
                Runnable r3 = new Runnable() {
                    public void run() {
                        System.out.println(Thread.currentThread() + "-> stage1");
                        try {
                            Thread.sleep(800);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        phaser.arriveAndAwaitAdvance();
                        System.out.println(Thread.currentThread() + "-> stage2");
                        try {
                            Thread.sleep(900);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        phaser.arriveAndAwaitAdvance();
                        System.out.println(Thread.currentThread() + "-> stage3");
                    }
                };
                
                ExecutorService pool = Executors.newCachedThreadPool();
                pool.execute(r1);
                pool.execute(r2);
                pool.execute(r3);
                pool.shutdown();
                
                
        f.


        g.
        
        
    9)线程封闭(Thread Confinement):
        原理: 不共享数据,仅在单线程内访问数据,不需要使用同步.是实现线程安全的最简单方式之一.
        a.Ad-hoc线程封闭:
            指维护线程封闭性的职责完全由程序实现来承担. 通常不在程序中使用.

        b.栈封闭:
            线程封闭的特例.在栈封闭中,只能通过局部变量才能访问对象.

        c.ThreadLocal:
            ThreadLocal类包含一个Map缓存,用于存储每一个线程的局部变量.变量与线程绑定.也就是将状态和线程关联起来.
            ThreadLocal用来存放线程的局部变量,每个线程都有单独的局部变量,彼此间不会共享.用来隔离多个线程间的共享冲突.
            ThreadLocal将需要并发访问的资源复制多份,每个线程拥有一份自己的资源副本,即没必要对该变量进行同步.
            使用ThreadLocal类为每个使用该变量的线程都提供一个变量值的副本,使每个线程都可以独立的改变自己的副本,而不会和其他线程的副本冲突.
            ThreadLocal通常当做静态域来使用.
            
            主要方法:
                public T get(): 返回当前线程的局部变量;
                public void remove(): 删除此线程局部变量中当前线程的值;
                public void set(T value): 设置当前线程的局部变量;
                protected T initialValue(): 返回当前线程的局部变量的初始值;

5.线程池


    创建一个新的线程需要一定的开销,因为涉及与操作系统的交互.若程序中需要创建大量的生命期很短的线程,应该使用线程池.
    创建大量线程会大大降低性能甚至使虚拟机崩溃.应该使用一个线程数'固定的'线程池以限制并发线程的数量.
    线程池通常包含许多准备运行的空闲线程.需要使用线程时向线程池请求一个线程,免去了创建线程的开销,使用完毕后将线程归还给线程池.
    同时,线程池还可以限制最大线程数,当线程池内的线程被用完后,向线程池请求线程的请求将阻塞,直到有空闲线程可供使用.

    1)概念:
        线程池: 指管理一组同构工作线程的资源池.
            线程池是与工作队列(Queue)密切相关的,其中在工作队列中保存了所有等待执行的任务.
            工作者线程(Thread)的任务很简单: 从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务.
            '在线程池中执行任务'比'为每个任务分配一个线程'的优势在于:
                1.通过重用现有的线程而不是创建新线程,可在处理多个请求时分摊在线程创建和销毁过程中产生的巨大开销;
                2.当请求到达时,工作线程通常已经存在,因此不会由于等待创建线程而延迟任务的执行,从而提高了响应时间;


    2)组成和创建:
        a.线程池的组成部分:
            管理器,工作线程,任务接口,等待队列.
            Executor接口表示线程池,它的execute(Runnable command)方法用于提交Runnable类型参数command的run()方法所指定的任务,
            线程池会调度空闲的线程来执行该任务.
            Executor接口的子接口ExecutorService具有管理线程池的一些方法;
                Future<T> submit(Callable<T> task):  用于向线程池提交任务,类似Executor接口的execute(Runnable command)方法;
                Future<?> submit(Runnable task):  用于向线程池提交任务,类似Executor接口的execute(Runnable command)方法;
                Future<T> submit(RUnnable task, T result):  用于向线程池提交任务;
                以上submit()方法支持异步运算,都会返回表示异步运算结果的Future对象.

            ExecutorService接口的实现类ThreadPoolExecutor能够执行普通任务,是一个基本实现;
            ExecutorService接口的实现类ScheduledThreadPoolExecutor能够执行定时任务;
              ExecutorService接口的实现类ForkJoinPool能够并行的执行任务;

        b.线程池的创建:
            Executors类提供静态工厂方法用于构建线程池.
            返回ExecutorService对象,代表一个线程池.可执行Runnable或Callable对象代表的线程;
                  ExecutorService newFixedThreadPool(); //创建一个固定长度的线程池;包含固定数量的线程,空闲线程会一直被保留;
                  ExecutorService newCachedThreadPool(); //创建一个可缓存的线程池;必要时创建新线程,空闲线程会被保留60秒;
                  ExecutorService newSingleThreadExecutor(); //一个单线程的Executor,创建单个工作线程来执行任务;

              返回ScheduledExecutorService对象,代表一个线程池,可在指定延迟后执行线程;
                  ScheduledExecutorService newScheduledThreadPool(); //用于预定执行而构建的固定线程池,替代java.util.Timer;
                ScheduledExecutorService newSingleThreadScheduledExecutor(); //用于预定执行而构建的单线程池;

            返回ExecutorService对象,代表一个线程池.可充分利用多CPU并行的能力.
                ExecutorService newWorkStealingPool(int parallelism); //创建持有足够线程的线程池来支持给定的并行级别;
                ExecutorService newWorkStealingPool(); //若当前主机有4个CPU,则目标并行级别被设置为4;


    3)使用:
        1.Executor接口/ExecutorService接口/ScheduledExecutorService接口
            Executor:
            ExecutorService:
            ScheduledExecutorService:
            
            线程池的基本使用:
                a.调用Executors类中的静态方法newCachedThreadPool()或newFixedThreadPool()创建一个线程池(ExecutorService);
                b.调用submit()提交Runnable或Callable对象;
                c.若想要取消一个任务,或提交Callable对象,就要保存好返回的Future对象;
                d.当不再提交任何任务时,调用shutdown();

        2.可扩展的基本线程池实现: ThreadPoolExecutor
            线程池的资源管理策略: 允许提供一个BlockingQueue来保存等待执行的任务.
                基本的任务排队方法有三种:
                    无界队列:
                        newFixedThreadPool(),newSingleThreadExecutor()默认情况下使用一个无界的LinkedBlockingQueue.
                        若任务持续快速的到达,且超过了线程池处理的速度,那么队列将无限的增加.

                    有界队列:
                        更好的策略是使用有界队列ArrayBlockingQueue,LinkedBlockingQueue,PriorityBlockingQueue.
                        有界队列有助于避免资源耗尽.在使用有界工作队列时,队列大小与线程池大小必须一起调节.
                        以避免当队列填满后,新任务无法保存的问题.

                    同步移交(Synchronous Handoff):
                        对于非常大的或无界的线程池,可使用SynchronousQueue来避免任务排队,避免直接将任务从生产者移交给工作者线程.
                        SynchronousQueue不是一个真正的队列,而是一种在线程间进行移交的机制.要将一个元素放入SynchronousQueue中,
                        必须有另一个线程正在等待接受这个元素.若没有线程正在等待,并且线程池的当前容量小于最小值,
                        那么ThreadPoolExecutor将创建一个新的线程,否则根据饱和策略,这个任务将被拒绝.
                        只有当线程池是无界的或可以拒绝任务时,SynchronousQueue才有实际价值.
                        在newCachedThreadPool工厂方法中就使用SynchronousQueue.

        3.可定期执行的线程池实现: ScheduledThreadPoolExecutor
              ScheduledExecutorService接口具有为预定执行或重复执行任务而设计的方法.是一种允许使用线程池机制的java.util.Timer的泛化.
              Executors类的以下方法将返回实现了ScheduledExecutorService接口的对象.
                  ScheduledExecutorService newScheduledThreadPool(int threads) //返回一个线程池,使用给定的线程数来调度任务
                  ScheduledExecutorService newSingleThreadScheduledExecutor() //返回一个执行器,在一个单独线程中调度任务

        4.可并行执行的线程池实现: ForkJoinPool
            Fork/Join框架:
                利用多核处理器,完成并行计算.将一个大任务分拆为多个小任务并行计算执行,再把多个小任务的运行结果合并成总的计算结果.
                分治算法:是一种设计方法,将问题划分为较小的问题.可采用递归方式重复该过程,直到需要解决的问题变得很小,可以直接解决.
                工作窃取算法:确定要执行的任务.

                组件:
                    ForkJoinPool:并行线程池.ForkJoinPool是ExecutorService的实现类,是一种特殊的线程池.
                    ForkJoinTask:所有Fork/Join任务的基本抽象类.代表一个可并行,合并的任务,是一个抽象类.它有三个抽象子类:
                        RecursiveAction: 没有返回值的任务;
                        RecursiveTask: 有返回值的任务;
                        CountedCompleter: 任务完成时触发另一任务;
                构造:
                    ForkJoinPool(int parallelism): 创建一个包含parallelism个并行线程的ForkJoinPool;
                    ForkJoinPool(): 以Runtime.availableProcessors()方法的返回值作为parallelism参数来创建ForkJoinPool;

                通用池功能:
                    ForkJoinPool commonPool(): 返回一个通用池,通用池的运行状态不受shutdown()或shutdownNow()方法的影响;
                    int getCommonPoolParallelism(): 返回通用池的并行级别;

                重要方法:
                    void execute(ForkJoinTask<?> task) //将任务发送给ForkJoinPool后立即返回
                    void execute(Runnable task) //
                    T invoke(ForkJoinTask<T> task) //将任务发送给ForkJoinPool后,当任务执行完成后才能返回
                    List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) //
                    ForkJoinTask<T> submit(ForkJoinTask<T> task) //将任务发送给ForkJoinPool后立即返回一个Future,用以控制任务状态且获得结果
                    ForkJoinTask<T> submit(Callable<T> task) //
                    ForkJoinTask<?> submit(Runnable task) //

        5.控制任务组: CompletionService接口/ExecutorCompletionService类:
            将任务的执行与任务结果的处理解耦.
            CompletionService接口在内部使用了一个执行器Executor,并且提供submit()方法将任务发送给CompletionService接口,
            还提供了poll()方法和take()方法来获取这些任务的结果.提供这些结果的顺序与任务执行完毕的顺序相同.
                构造:
                    ExecutorCompletionService(Executor executor) //使用指定的执行器创建,并将LinkedBlockingQueue作为完成队列
                    ExecutorCompletionService(Executor executor, BlockingQueue<Future<V>> completionQueue) //

                重要方法:
                    Future<V> poll() //获取并移除表示下一个已完成任务的Future,若不存在这样的任务,则返回null.
                    Future<V> poll(long timeout, TimeUnit unit) //获取并移除表示下一个已完成任务的Future,若不存在这样的任务,将等待指定的时间
                    Future<V> take() //获取并移除表示下一个已完成任务的Future,若不存在这样的任务,则等待
                    Future<V> submit(Callable<V> task) //提交要执行的值返回任务,并返回表示挂起的任务结果的Future
                    Future<V> submit(Runnable task, V result) //提交要执行的Runnable任务,并返回一个表示任务完成的Future,可以提取或轮询此任务

              示例:
                List<Callable<T>> tasks = new ArrayList<>();
                ExecutorCompletionService<T> service = new ExecutorCompletionService<>(executor);
                for(Callable<T> task: tasks)
                    service.submit(task);

                for(int i=0; i<tasks.size(); i++)
                    processFurther(service.take().get());


    4)API总结:
        Interface:
            Executor:
                void execute(Runnable command)  //在未来某个时间执行给定的任务command

        
            ExecutorService:
                boolean awaitTermination(long timeout, TimeUnit unit)  //等待所有任务执行完成,线程池关闭
                List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)  //执行给定的任务,当所有任务完成时,返回Future列表
                List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) //为执行任务设定一个时限
                T invokeAny(Collection<? extends Callable<T>> tasks) //执行给定的任务,若某个任务已完成,则返回结果
                T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) //为执行任务设定一个时限
                void shutdown()  //预备关闭线程池,直到所有任务执行完毕
                boolean isShutdown()  //若执行程序已关闭,则返回true
                boolean isTerminated() //判断线程池是否关闭,若关闭返回true,否则返回false
                List<Runnable> shutdownNow()  //终止已经开始执行的任务,立即关闭线程池
                Future<T> submit(Callable<T> task)  //用于向线程池提交任务,类似Executor接口的execute(Runnable command)方法
                   Future<?> submit(Runnable task)  //用于向线程池提交任务
                Future<T> submit(Runnable task, T result) //用于向线程池提交任务
                

            ScheduledExecutorService:
                ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) //创建并执行有返回任务,在给定延迟后启用
                ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit) //创建并执行无返回任务,在给定延迟后启用
                ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit) //
                ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit) //
        
            
            CompletionService:
                Future<V> poll() //
                Future<V> poll(long timeout, TimeUnit unit) //
                Future<V> submit(Callable<V> task) //
                Future<V> submit(Runnable task, V result) //
                Future<V> take() //


        Class:
            ThreadPoolExecutor:
                构造:
                    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                        BlockingQueue<Runnable> workQueue)
                    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                        BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
                    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
                    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                    BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
                重要方法:
                    void allowCoreThreadTimeOut(boolean value) //
                    void allowsCoreThreadTimeOut() //
                    void awaitTermination(long timeout, TimeUnit unit) //
                    void execute(Runnable command) //在未来的某个时间执行给定任务
                    int getActiveCount() //返回主动执行任务的近似线程数
                    long getCompletedTaskCount() //返回已完成执行的近似任务总数
                    long getKeepAliveTime(TimeUnit unit) //返回线程保持活动的时间
                    int getCorePoolSize() //返回核心线程数
                    int getLargestPoolSize() //返回曾经同时位于池中的最大线程数
                    int getMaximumPoolSize() //返回允许的最大线程数
                    int getPoolSize() //返回池中的当前线程数
                    BlockingQueue<Runnable> getQueue() //返回任务队列
                    RejectedExecutionHandler getRejectedExecutionHandler() //返回用于未执行任务的当前处理程序
                    long getTaskCount() //返回曾计划执行的近似任务总数
                    ThreadFactory getThreadFactory() //返回线程工厂
                    boolean isShutdown() //
                    boolean isTerminated() //
                    boolean isTerminating() //
                    int prestartAllCoreThreads() //启动所有核心线程,使其处于等待工作的空闲状态
                    boolean prestartCoreThread() //启动核心线程,使其处于等待工作的空闲状态
                    void purge() //
                    boolean remove(Runnable task) //尝试从任务队列中移除未开始执行的任务
                    void setCorePoolSize(int corePoolSize) //设置核心线程数
                    void setKeepAliveTime(long time, TimeUnit unit) //设置线程在终止前可以保持空闲的时间限制
                    void setMaximumPoolSize(int maximumPoolSize) //设置允许的最大线程数
                    void setRejectedExecutionHandler(RejectedExecutionHandler handler) //设置处理程序
                    void setThreadFactory(ThreadFactory threadFactory) //设置线程工厂
                    void shutdown() //不接受新任务,执行完所有任务,关闭线程池
                    List<Runnable> shutdownNow() //尝试停止所有任务,返回未执行完毕的任务列表,关闭线程池


            ScheduledThreadPoolExecutor:
                构造:
                    ScheduledThreadPoolExecutor(int corePoolSize) //
                    ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) //
                    ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) //
                    ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) //

                重要方法:
                    void execute(Runnable command) //
                    BlockingQueue<Runnable> getQueue() //
                    boolean remove(Runnable task) //
                    ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) //
                    ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) //
                    ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) //
                    ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) //
                    void shutdown() //
                    List<Runnable> shutdownNow() //
                    Future<T> submit(Callable<T> task) //
                    Future<?> submit(Runnable task) //
                    Future<T> submit(Runnable task, T result) //


            ForkJoinPool:
                构造:
                    ForkJoinPool() //
                    ForkJoinPool(int parallelism) //
                    ForkJoinPool(int parallelism, ForkJoinPool.ForkJoinWorkerThreadFactory factory,
                                    Thread.UncaughtExceptionHandler handler, boolean asyncMode)

                重要方法:
                    static ForkJoinPool commonPool() //返回线程池实例
                    static int getCommonPoolParallelism() //
                    static void managedBlock(ForkJoinPool.ManagedBlocker blocker) //

                    boolean awaitQuiescence(long timeout, TimeUnit unit) //
                    boolean awaitTermination(long timeout, TimeUnit unit) //
                    void execute(ForkJoinTask<?> task) //
                    void execute(Runnable task) //
                    int getActiveThreadCount() //
                    boolean getAsyncMode() //
                    ForkJoinPool.ForkJoinWorkerThreadFactory getFactory() //
                    int getParallelism() //
                    int getPoolSize() //
                    int getQueuedSubmissionCount() //
                    long getQueuedTaskCount() //
                    int getRunningThreadCount() //
                    long getStealCount() //
                    Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() //
                    boolean hasQueuedSubmissions() //
                    T invoke(ForkJoinTask<T> task)  //
                    List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) //
                    boolean isQuiescent() //
                    boolean isShutdown() //
                    boolean isTerminated() //
                    boolean isTerminating() //
                    void shutdown() //
                    List<Runnable> shutdownNow() //
                    ForkJoinTask<T> submit(Callable<T> task) //
                    ForkJoinTask<T> submit(ForkJoinTask<T> task) //
                    ForkJoinTask<?> submit(Runnable task) //
                    ForkJoinTask<T> submit(Runnable task, T result) //


            ExecutorCompletionService:
                构造:
                    ExecutorCompletionService(Executor executor) //
                    ExecutorCompletionService(Executor executor, BlockingQueue<Future<V>> completionQueue) //

                重要方法:
                    Future<V> poll() //获取并移除表示下一个已完成任务的Future,若不存在这样的任务,则返回null
                    Future<V> poll(long timeout, TimeUnit unit) //获取并移除表示下一个已完成任务的Future,若不存在这样的任务,等待指定时间
                    Future<V> submit(Callable<V> task) //提交可返回任务
                    Future<V> submit(Runnable task, V result) //提交无返回的任务
                    Future<V> take() //获取并移除下一个已完成的任务


            Executors:
                static Callable<Object> callable(PrivilegedAction<?> action)
                static Callable<Object> callable(PrivilegedExceptionAction<?> action)
                static Callable<Object> callable(Runnable task)
                static Callable<T> callable(Runnable task, T result)
                static ThreadFactory defaultThreadFactory()
                static ExecutorService newCachedThreadPool()
                static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
                static ExecutorService newFixedThreadPool(int nThreads)
                static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
                static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
                static ScheduledExecutorService    newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
                static ExecutorService newSingleThreadExecutor()
                static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
                static ScheduledExecutorService    newSingleThreadScheduledExecutor()
                static ScheduledExecutorService    newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
                static ExecutorService newWorkStealingPool()
                static ExecutorService newWorkStealingPool(int parallelism)
                static <T> Callable<T> privilegedCallable(Callable<T> callable)
                static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable)
                static ThreadFactory privilegedThreadFactory()
                static ExecutorService unconfigurableExecutorService(ExecutorService executor)
                static ScheduledExecutorService    unconfigurableScheduledExecutorService(ScheduledExecutorService executor)

        Fork-Join框架:
            ForkJoinPool类:
            ForkJoinTask类:
            CountedCompleter类:
            RecursiveAction类:
            RecursiveTask类:


    5)线程池的应用:

6.线程相关异常及处理


    BrokenBarrierException: //
    
    CancellationException: //

    CompletionException: //

    ExecutionException: //

    RejectedExecutionException: //

    TimeoutException: //

    InterruptedException: //

    UncaughtExceptionHandler:  //当Thread因未捕获的异常而突然终止时,调用处理程序的接口.

    UncaughtException:  //当线程组中的线程因为一个未捕获的异常而停止,并且线程没有安装特定Thread.UncaughtExceptionHandler.

    ConcurrentModificationException: //并发修改异常.

    IllegalThreadStateException: //在线程启动后,再调用该线程的setDaemon()方法,会导致该异常发生.
                                 //对已开始执行的线程调用start()方法也会导致该异常发生.

    IllegalMonitorStateException: //对一个对象的wait(),notify(),notifyAll()方法的调用应放在同步代码块中,否则导致此异常

7.并发API总结


    
    java.util.concurrent.*;
        Interfaces:
            BlockingQueue;
            BlockingDeque;
            Callable;
            CompletionService;
            CompletionStage;
            ConcurrentMap;
            ConcurrentNavigableMap;
            Delayed;
            Executor;
            ExecutorService;
            Future;
            RejectedExecutionHandler;
            RunnableFuture;
            RunnableScheduledFuture;
            ScheduledExecutorService;
            ScheduledFuture;
            ThreadFactory;
            TransferQueue;

        Classes:
            AbstractExecutorService;
            Executors;
            ThreadPoolExecutor;
            ScheduledThreadPoolExecutor;
            ForkJoinPool;
            ForkJoinTask;
            CountedCompleter;
            RecursiveAction;
            RecursiveTask;
            ForkJoinWorkerThread;

            ArrayBlockingQueue;
            SynchronousQueue;
            PriorityBlockingQueue;
            LinkedBlockingDeque;
            LinkedBlockingQueue;
            LinkedTransferQueue;
            DelayQueue;
            ConcurrentLinkedDeque;
            ConcurrentLinkedQueue;

            FutureTask;
            CompletableFuture;
            ExecutorCompletionService;

            ConcurrentHashMap;
            ConcurrentSkipListMap;
            CopyOnWriteArraySet;
            ConcurrentSkipListSet;
            CopyOnWriteArrayList;

            CountDownLatch;
            CyclicBarrier;
            Exchanger;
            Phaser;
            Semaphore;
            
            ThreadLocalRandom;
            
        Enums:
            TimeUnit;

    java.util.concurrent.locks.*;
        Interfaces:
            Condition;
            Lock;
            ReadWriteLock;

        Classes:
            AbstractOwnableSynchronizer;
            AbstractQueuedLongSynchronizer;
            AbstractQueuedSynchronizer;
            LockSupport;
            ReentrantLock;
            ReentrantReadWriteLock;
            ReentrantReadWriteLock.ReadLock;
            ReentrantReadWriteLock.WriteLock;
            StampedLock;
    
    java.util.concurrent.atomic.*;
        Interfaces:
        Classes:
            AtomicBoolean;
            AtomicInteger;
            AtomicIntegerArray;
            AtomicIntegerFieldUpdater;
            AtomicLong;
            AtomicLongArray;
            AtomicLongFieldUpdater;
            AtomicMarkableReference;
            AtomicReference;
            AtomicReferenceArray;
            AtomicReferenceFieldUpdater;
            AtomicStampedReference;
            DoubleAccumulator;
            DoubleAdder;
            LongAccumulator;
            LongAdder;

8.并发程序的性能调优


    代码被阅读的次数远多于被编写的次数.在编程时,与其他人交流相对于与计算机交流而言,要重要的多,因此代码的可读性至关重要.

    使用多线程常是为了充分利用多核处理器的计算能力,因此在并发程序性能的讨论中,通常更多的将侧重点放在吞吐量和可伸缩性上.
    Amdahl定律告诉我们,程序的可伸缩性取决于在所有代码中必须被串行执行的代码比例.因为Java程序中串行操作的主要来源是独占式的资源锁,
    因此通常可以通过以下方式来提升可伸缩性:减少锁的持有时间,降低锁的粒度,采用非独占的锁或非阻塞锁来代替独占锁.

    使用多线程会引入额外的性能开销,造成这些开销的操作包括:线程之间的协调(加锁,触发信号,内存同步等),增加的上下文切换,
    线程的创建和销毁,线程的调度等.若不当使用线程,那么这些开销甚至会超过由于提高吞吐量,响应性或计算能力所带来的性能提升.

    要想通过并发来获得更好的性能,需要努力做好两件事情:更有效的利用现有处理资源,以及在出现新的处理资源时使程序尽可能的利用这些新资源.
    可伸缩性:当增加计算资源时(例如CPU,内存,存储容量,I/O带宽),程序的吞吐量或处理能力能够相应的增加.
    在并发程序中,对可伸缩性的最主要威胁就是独占式的资源锁.
    降低锁的竞争程度的三种方式:
        减少锁的持有时间;
        降低锁的请求频率;
        使用带有协调机制的独占锁,这些机制允许更高的并发性;

9.写代码的技巧   

10.扩展知识
   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光明矢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值