JDK下Concurrent包部分介绍

Executor

                   Executor接口是所有线程执行类的父接口,这个接口可以建立线程池,然后执行线程。

                   Executor框架的最核心的类是ThreadPoolExecutor,它是线程池的实现类,创建ThreadPoolExecutor一般使用Executors工厂模式创建,Executors类提供了一系列工厂方法用于创先线程池:

  • public static ExecutorService newFixedThreadPool(int nThreads)创建固定数目线程的线程池,表示最多创建nThreads个线程,如果传入的任务数大于nThreads时不会创建新的线程,而是阻塞等待有空闲线程执行。

  • public static ExecutorService newCachedThreadPool()创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60秒钟未被使用的线程。

  • public static ExecutorService newSingleThreadExecutor()创建一个单线程化的Executor。

  • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

常用方法:

  • shutDown():关闭执行器,在关闭前允许执行以前提交的任务执行器执行完。调用shutDown()后,再发送任务给Executor将会被拒绝,抛出RejectExecutionException异常。

  • shutdownNow() :立即关闭执行器,阻止等待任务启动,并试图停止当前正在执行的任务。返回等待执行的任务列表。

  • isShutdown():调用shutDown()后,返回true。

  • isTerminated():调用shutDown()后,并且执行器完成了关闭过程,返回true。

  • getPoolSize():获取当前线程池的线程数量

  • getActiveCount():获取线程池中活动线程的数量

  • getCompleteCount():获取线程池中完成的任务数。

ExecutorService

                   ExecutorService可以帮助我们建立线程池。

BlockingQueue

                  阻塞队列跟信号量差不多,比如生产者消费者问题中,如果不用阻塞队列,采用非阻塞队列存放产品的话,需要用synchronized来对produce()和consume()操作进行同步,而采用阻塞队列就不需要这样了,它自身就带同步功能,当空时自然不能取,满时自然不能继续生产,这就是BlockingQueue的作用。

                  阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。

Semphore

                  信号量Semaphore是一个计数信号量,用来保护一个或多个共享资源的访问,是Java Concurrent包下提供的另一种同步方式,就像synchronized一样的呢,它就是替代synchronized的。 Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

Future

                  可以得到Callable接口与Runnable接口执行的返回值,也可以调用cancel方法取消线程的执行。

                  Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

也就是说Future提供了三种功能:

                  1)判断任务是否完成;

                  2)能够中断任务;

                  3)能够获取任务执行结果。

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

Callable

                  Callable接口与Runnable接口实现的功能都是一样的,不过它有返回值的,我们可以知道线程是否执行完毕呢。通常与Future,FutureTask连着用。

ThreadPoolExecutor

                   CylicBarrier

                  ThreadLocal

CountDownLatch

                  CountDownLatch是Java Concurrent包下提供的同步辅助类。在完成一组正在其他线程中执行的操作之前,它允许线程一直等待。

                  和Semaphore类似,它使用一个整数进行初始化,Semaphore中的计算表示可以同步访问共享数据的线程数,CountDownLatch中的计算表示线程要等待的操作数数目。

                  CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

操作方法

  • 构造函数CountDownLatch(int count),count表示要等待的操作数的数目。
  • await()方法,阻塞等待,需要其他线程完成期待的操作,直到count为0。
  • countDown()方法,当某一个操作完成后,调用此方法,count数减一。

下面对上面说的三个辅助类进行一个总结:

                  1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

                  2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

ThreadFactory

    ThreadFactory是一个接口,就是一个工厂模式的典型。

  • 线程工厂(ThreadFactory接口)

    在创建线程的时候,我们当然也能使用工厂模式来生产Thread,ThreadFactory是用来实现创建线程的工厂模式接口,其实它只有一个方法Thread newThread(Runnable r),所以这个接口没多大用,可以自己编写新接口。

    使用ThreadFactory工厂这样就能替代默认的new Thread,而且在自定义工厂里面,我们能创建自定义化的Thread,并且计数,或则限制创建Thread的数量,给每个Thread设置对应的好听的名字,或则其他的很多很多事情。

  • ThreadFactory在并发中的使用

    在Java中使用ThreadFactory最多应该就是Executor框架和Fork\/Join框架了,使用ThreadFactory创建各种线程池中的线程。在Executor框架中,使用Executors创建线程池执行器的时候,也可以传入ThreadFactory对象,执行器将会使用该ThreadFactory对象来创建线程。

    如:newCachedThreadPool(ThreadFactory threadFactory)

Condition(代替同步锁synchronized )

                  发包下的提供Lock锁,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇之上,使用Lock如何处理线程通信。

                  那么引入本篇的主角,Condition,Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

                  在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。

                  Condition的强大之处在于它可以为多个线程间建立不同的Condition, 使用synchronized\/wait()只有一个阻塞队列,notifyAll会唤起所有阻塞队列下的线程,而使用lock\/condition,可以实现多个阻塞队列,signalAll只会唤起某个阻塞队列下的阻塞线程。

ReentrantLock(可重入锁)

                  可重入锁与synchronized比较?

                  由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:

                  1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。

                  2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

                  3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。

ThreadLocal

                  线程私有变量,就是我们在建立类的时候可以把成员变量声明为线程私有的, 最常见的ThreadLocal使用场景为 用来解决 数据库连接、Session管理等。 ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

                  准确的说,应该是ThreadLocal类型的变量内部的注册表(Map<Thread,T>)发生了变化,但ThreadLocal类型的变量本身的确是一个,这才是本质!

                  虽然ThreadLocal变量只有一个,各个线程共享,但是ThreadLocal内部维护一个Map<Thread,T>,通过线程Id每个线程都维护唯一的一个变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

、小H

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

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

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

打赏作者

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

抵扣说明:

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

余额充值