Java Concurrent并发包 概括

Java并发包

https://blog.csdn.net/Dax1n/article/details/74544299



java.util.concurrent

http://www.android-doc.com/reference/java/util/concurrent/package-summary.html

concurrent包中几个重要容器接口和其实现类介绍

(1)BlockQueue<E> 阻塞队列{线程安全的}


BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。

BlockingQueue 具有 4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:

 

四组不同的行为方式解释:

    抛异常:如果试图的操作无法立即执行,抛一个异常。
    特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
    阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。

    超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告 该操作是否成功(典型的是 true / false)。

无法向一个 BlockingQueue 中插入 null。如果你试图插入 null,BlockingQueue 将会抛出一个 NullPointerException。

实现该接口的类和接口:

ArrayBlockingQueue<E>,     数组实现,元素有限,不接受null,实现Serializable,可序列化

DelayQueue<E extends Delayed>,   链表实现?,元素无限,不接受null,元素必须是实现Delayed接口的对象,不可序列化

SynchronousQueue<E>  只容纳一个元素 ,多方多取会阻塞,实现Serializable,可序列化

PriorityBlockingQueue<E> 不接受null,元素必须是实现Comparable接口的对象,实现Serializable,可序列化

LinkedBlockingQueue<E>链表实现,如果没有定义上限将使用 Integer.MAX_VALUE 作为上限,实现Serializable,可序列化

LinkedBlockingDeque<E>,   链表实现,实现Serializable,可序列化

BlockingDeque<E>,  (接口)


(2)BlockDeque<E> 阻塞双端队列 {线程安全的}

在双端队列的两端都可以插入和提取元素。


实现该接口的类和接口:

        LinkedBlockingDeque<E> 链表实现,不接受null ,线程安全,实现了Serializable可序列化


以上都是阻塞的队列,下面两个是非阻塞对列都可序列化都是线程安全的,此实现采用了有效的“无等待 (wait-free)”算法,该算法基于 Maged M. Michael 和 Michael L. Scott 合著的 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms 中描述的算法。

        ConcurrentLinkedQueue  继承Queue、 元素无限、线程安全,可序列化、非阻塞、不接受null元素

        ConcurrentLinkedDeque 在API中未找到

(3)ConcurrentMap<K,V> 并发映射

继承子Map接口除了Map的一些方法外还有一些额外的原子性方法。

实现该接口的类和接口:

ConcurrentHashMap<K,V>  可序列化,线程安全的,不接受null

ConcurrentNavigableMap<K, V> 接口

ConcurrentSkipListMap<K, V> 可序列化,实现上面map接口,不接受null值,线程安全的

(4)ConcurrentSkipListSet<E>   与set容器有关的一个类

ConcurrentSkipListSet<E> 可序列化,线程安全的,不接受null

线程间同步工具

(1)CountDownLatch 闭锁  不可序列化

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

用给定的计数 初始化 CountDownLatch,countDown() 每被调用一次,这一数量就减一所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程 ,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。

(2)栅栏 CyclicBarrier 不可序列化

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

awit(int)等待 ;reset()重置

(3)信号量 Semaphore  可序列化

aquire() 获取一个许可 如果获取不到则被阻塞

release() 归还一个许可

(4) 交换机 Exchanger<V>


Exchanger 可以当作两个线程的汇合点,当一个线程提前到达exchanger点处调用exchange返回,此线程会阻塞等待另一个线程,当另一个线程到达此汇合点时调用同一个exchanger的exchanger方法,此时交换两个两个线程提交的对象,然后让两个线程通过,继续运行。

Exchanger exchanger = new Exchanger();  
  
ExchangerRunnable exchangerRunnable1 =  
        new ExchangerRunnable(exchanger, "A");  
  
ExchangerRunnable exchangerRunnable2 =  
        new ExchangerRunnable(exchanger, "B");  
  
new Thread(exchangerRunnable1).start();  
new Thread(exchangerRunnable2).start();  

public class ExchangerRunnable implements Runnable{  
  
    Exchanger exchanger = ;  
    Object    object    = ;  
  
    public ExchangerRunnable(Exchanger exchanger, Object object) {  
        this.exchanger = exchanger;  
        this.object = object;  
    }  
  
    public void run() {  
        try {  
            Object previous = this.object;  
  
            this.object = this.exchanger.exchange(this.object);  
  
            System.out.println(  
                    Thread.currentThread().getName() +  
                    " exchanged " + previous + " for " + this.object  
            );  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  
Executor 执行器相关的

Executor 根接口

ExecutorService 接口

ScheduledExecutorService 接口

AbstractExecutorService 类
ScheduledThreadPoolExecutor 类
ThreadPoolExecutor 类

Executor接口表示一个异步执行机制,使我们能够在后台执行任务提交的实现了runnable 接口的任务,唯一的方法

 void execute(Runnable command) ; 执行Runnable 方法

ExecutorService 实现了Executor接口 ,提供了invoke、shutdown、submit 方法, 有些方法会返回Future 对象 表示执行结果和执行状态。 invoke方法接受实现了callable方法的对象集合,submit既支持Runnable对象也支持Callable对象。


一旦该线程将任务委派给 ExecutorService,该线程将继续它自己的执行,独立于该任务的执行。

其之类有 ScheduledExecutorService,   ScheduledThreadPoolExecutor, ThreadPoolExecutor; 创建方式如下(采用工厂方式)

ExecutorService executorService1 = Executors.newSingleThreadExecutor();  
  
ExecutorService executorService2 = Executors.newFixedThreadPool(10);  
  
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);  

使用完 ExecutorService 之后应该将其关闭,以使其中的线程不再运行。
比如,如果应用是通过一个 main() 方法启动的,之后 main 方法退出了应用,如果应用有一个活动的 ExexutorService 它将还会保持运行。ExecutorService 里的活动线程阻止了 JVM 的关闭。
要终止 ExecutorService 里的线程你需要调用 ExecutorService 的 shutdown() 方法。ExecutorService 并不会立即关闭,但它将不再接受新的任务,而且一旦所有线程都完成了当前任务的时候,ExecutorService 将会关闭。在 shutdown() 被调用之前所有提交给 ExecutorService 的任务都被执行。

如果想要立即关闭 ExecutorService,可以调用 shutdownNow() 方法。这样会立即尝试停止所有执行中的任务,并忽略掉那些已提交但尚未开始处理的任务。无法担保执行任务的正确执行。可能它们被停止了,也可能已经执行结束。


返回结果Future 接口介绍

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。

get()、cancel()、isCancelled()、isDone();


ThreadPoolExecutor 类

ThreadPoolExecutor 使用其内部池中的线程执行给定任务(Callable 或者 Runnable)。

线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供更强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。

线程池执行器的创建


int  corePoolSize  =    5;  
int  maxPoolSize   =   10;  
long keepAliveTime = 5000;  
  
ExecutorService threadPoolExecutor =  
        new ThreadPoolExecutor(  
                corePoolSize,  
                maxPoolSize,  
                keepAliveTime,  
                TimeUnit.MILLISECONDS,  
                new LinkedBlockingQueue<Runnable>()  
                );  
ScheduledExecutorService接口

ScheduledExecutorService 是一个 ExecutorService, 它能够将任务延后执行,或者间隔固定时间多次执行

此接口的实现类ScheduledThreadPoolExecutor

其中的ThreadPoolExecutor在给点的延时时间后执行或者周期执行。

ForkJoinPool // 不想弄了 android api中未找到


java.util.concurrent.locks 锁包解析

(1)Lock 接口

Lock 接口具有以下主要方法:

lock()

unlock()

tryLock() 试图立即锁定 Lock 实例。如果锁定成功,它将返回 true,如果 Lock 实例已被锁定该方法返回 false,这一方法永不阻塞。

tryLock(long timeout, TimeUnit timeUnit)  等待锁timeout时间,如果未获得则返回false,获得锁返回true。

lockInterruptibly()     如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断

实现该接口的类和接口:

ReentrantLock  可序列化

ReentrantReadWriteLock.ReadLock   可序列化

ReentrantReadWriteLock.WriteLock   可序列化


ReentrantLock的使用demo ,一般会在finally块中写unlock()以防死锁。。

Lock lock = new ReentrantLock();  
  
lock.lock();  
try
{
   //critical section  
}catch()
finally
{
   lock.unlock();  
}

读写锁说明: 同时时刻之能读或者只能写,但可以多个线程同时读取,如果写的话只能有一个线程进行操作,

(2)Condition接口

通过 newCondition ()方法获得一个Condition实例。

Condition 替代了 Object 监视器方法的使用。 Condition的 await()和signal(),signalAll()方法替代了wait 和notify()、notifyAll()方法,以原子方式 释放相关的锁,并挂起当前线程!

Lock和synchronize 的却别

synchronized是托管给JVM执行的,而lock是java写的控制锁的代码,在Java1.5中,synchronize是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象,性能更高一些。但是到了Java1.6,发生了变化。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地。

synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。

而Lock用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是CAS操作(Compare and Swap)(非阻塞式算法)。我们可以进一步研究ReentrantLock的源代码,会发现其中比较重要的获得锁的一个方法是compareAndSetState。这里其实就是调用的CPU提供的特殊指令。

synchronized和lock用途区别

synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程



java.util.concurrent.atomic

一个小型工具包,支持单变量上的无锁线程安全编程。 本质上,这个包中的类将volatile变量值,字段和数组元素的概念扩展为那些还提供了表单的原子条件更新操作的变量,使用无所算法(CAS)对变量进行原子性的操作。

该包中只有类,没有接口,包中的类如下

AtomicBoolean
AtomicInteger
AtomicIntegerArray
AtomicIntegerFieldUpdater<T>
AtomicLong
AtomicLongArray
AtomicLongFieldUpdater<T>
AtomicMarkableReference<V>
AtomicReference<V>
AtomicReferenceArray<E>
AtomicReferenceFieldUpdater<T,V>

AtomicStampedReference<V>

其中常用的方法有:

get(),set(),

getandset(),setandget(),

addAndGet(int delta),getAndAdd(int delta)

getAndDecrement(),decrementAndGet()

getAndIncrement(),incrementAndGet()

猜你喜欢

转载自blog.csdn.net/u012232736/article/details/79919450