关于Java并发的常用类回顾

来源:互联网 发布:配电网工程设计软件 编辑:程序博客网 时间:2024/06/06 03:27

volatile 关键字

  • 变量声明为volatile,表示这个变量是不稳定的,每次使用都去主存中读取
  • Volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值
  • 问题:两个线程分别读写volatile变量,线程A写入变量,线程B读取的时候会看到写入volatile变量之前所有可见的共享变量
  • Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成
  • volatile关键字用于声明简单类型变量,如int、float、 boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制:

    • 当变量的值由自身的上一个决定时,如n=n+1、n++ 等,volatile关键字将失效
    • 只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原子级别的

synchronizedList

  • 包裹了普通的ArrayList提供了线程安全的机制,类似Vector,所以到此为止synchronizedList与Vector的区别就是ArrayList与Vector的增量速度区别,所以需要线程安全操作时,增量比较快的时候推荐使用Vector
  • synchronizedList在迭代的时候,需要开发者自己加上线程锁控制代码
  • 因为迭代器涉及的代码没有在java api中没有加上线程同步代码

Executor框架

  • Executor 框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable 等。
  • 分类

    • Executors.newCachedThreadPool();
      • Executors.newFixedThreadPool(5);
      • Executors.newSingleThreadExecutor();
      • Executors.newScheduledThreadPool(3);
  • Callble任务

    • Callable 中的 call()方法类似 Runnable 的 run()方法,区别同样是有返回值,后者没有
    • Future.get()得到返回结果
  • 自定义线程池,可以用 ThreadPoolExecutor 类创建

    public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long         keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue)
  • 当有新的任务要处理时,先看线程池中的线程数量是否大于 corePoolSize,再看缓冲队列 workQueue 是否满,最后看线程池中的线程数量是否大于 maximumPoolSize。

Lock锁

  • Lock 接口有 3 个实现它的类:
    • ReentrantLock
    • ReetrantReadWriteLock.ReadLock
    • ReetrantReadWriteLock.WriteLock
  • Java 5 中引入了注入 AutomicInteger、AutomicLong、AutomicReference 等特殊的原子性变量类,它们提供的如:compareAndSet()、incrementAndSet()和getAndIncrement()等方法都使用了 CAS 操作
  • 条件变量Condition实现线程间协作
    • await()、signal()、signalAll()

阻塞队列

  • 阻塞队列的接口是 java.util.concurrent.BlockingQueue,它有多个实现类:ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue 等
  • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。

    • 默认情况下不保证访问者公平的访问队列,概念:先阻塞的消费者线程,可以先从队列里获取元素
  • LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。

  • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。

    • 默认情况下元素采取自然顺序排列,也可以通过比较器comparator来指定元素的排序规则
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列。

    • 队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素
  • SynchronousQueue:一个不存储元素的阻塞队列。

    • 每一个put操作必须等待一个take操作
  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

    • 相比其他的阻塞队列,LinkedBlockingDeque多了addFirst,addLast,offerFirst,offerLast,peekFirst,peekLast等方法

阻塞栈

  • 阻塞栈的接口java.util.concurrent.BlockingDeque
  • 多种实现

并发新特性—障碍器 CyclicBarrier

  • 创建一组任务,它们并发地执行工作,指定一个任务,该组任务全部执行结束,这个任务才得以执行

CountDownLatch类

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

信号量Semaphore

  • 可以通过使用信号量来自定义实现类似 Java 中的 synchronized、wait、notify 机制。
  • 以控制某个资源被同时访问的任务数,它通过acquire()获取一个许可,release()释放一个许可。如果被同时访问的任务数已满,则其他 acquire 的任务进入等待状态,直到有一个任务被 release 掉,它才能得到许可。
  • 注意是对并发访问的任务数进行监控,而不会保证线程安全

ps

  • CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

        CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

        而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

        CountDownLatch是不能重用的,而CyclicBarrier可以重用。

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

参考

  • http://www.infoq.com/cn/articles/java-blocking-queue/
  • http://www.cnblogs.com/dolphin0520/p/3920397.html
0 0
原创粉丝点击