Java多线程CountDownLatch原理

  categories:java资料, 资料  author:

CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。

CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。
CountDownLatch的用法

CountDownLatch典型用法1:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ,每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

CountDownLatch典型用法2:实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。
CountDownLatch的不足

CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

 

来源:http://www.cnblogs.com/skywang12345/p/3533887.html
里面有一个系列的文章介绍java多线程的源代码分析等, 非常好! 值得观看!

概要

前面对”独占锁”和”共享锁”有了个大致的了解;本章,我们对CountDownLatch进行学习。和ReadWriteLock.ReadLock一样,CountDownLatch的本质也是一个”共享锁”。本章的内容包括:
CountDownLatch简介
CountDownLatch数据结构
CountDownLatch源码分析(基于JDK1.7.0_40)
CountDownLatch示例

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3533887.html

CountDownLatch简介

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

CountDownLatch和CyclicBarrier的区别
(01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
(02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。
关于CyclicBarrier的原理,后面一章再来学习。
CountDownLatch函数列表

CountDownLatch(int count)阅读全文

Java 理论与实践 流行的原子

  categories:java资料  tags:  author:

在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待、无锁定的算法。在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化。请跟随并行专家 Brian Goetz 一起,了解这些新类如何使用 Java 语言开发高度可伸缩的无阻塞算法。您可以在本文的 论坛中与作者或其他读者共享您对本文的看法。(也可以通过单击文章顶部或者底部的 讨论链接来访问讨论。)

十五年前,多处理器系统是高度专用系统,要花费数十万美元(大多数具有两个到四个处理器)。现在,多处理器系统很便宜,而且数量很多,几乎每个主要微处理器都内置了多处理支持,其中许多系统支持数十个或数百个处理器。

要使用多处理器系统的功能,通常需要使用多线程构造应用程序。但是正如任何编写并发应用程序的人可以告诉你的那样,要获得好的硬件利用率,只是简单地在多个线程中分割工作是不够的,还必须确保线程确实大部分时间都在工作,而不是在等待更多的工作,或等待锁定共享数据结构。

问题:线程之间的协调

如果线程之间 需要协调,那么几乎没有任务可以真正地并行。以线程池为例,其中执行的任务通常相互独立。如果线程池利用公共工作队 列,则从工作队列中删除元素或向工作队列添加元素的过程必须是线程安全的,并且这意味着要协调对头、尾或节点间链接指针所进行的访问。正是这种协调导致了 所有问题。

标准方法:锁定

在 Java 语言中,协调对共享字段的访问的传统方法是使用同步,确保完成对共享字段的所有访问,同时具有适当的锁定。通过同步,可以确定(假设类编写正确)具有保护 一组给定变量的锁定的所有线程都将拥有对这些变量的独占访问权,并且以后其他线程获得该锁定时,将可以看到对这些变量进行的更改。弊端是如果锁定竞争太厉 害(线程常常在其他线程具有锁定时要求获得该锁定),会损害吞吐量,因为竞争的同步非常昂贵。(Public Service Announcement:对于现代 JVM 而言,无竞争的同步现在非常便宜。

基于锁定的算法的另一个问题是:如果延迟具有锁定的线程(因为页面错误、计划延迟或其他意料之外的延迟),则

阅读全文

用ScheduledThreadPoolExecutor替换Timer定时执行任务

  categories:java资料  author:

项目需要 每天几点 每周周几几点 每月几号几点定时执行任务

一。 用timer缺点非常大

Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。

但是Timer和TimerTask存在一些缺陷:

1:Timer只创建了一个线程。当你的任务执行的时间超过设置的延时时间将会产生一些问题。

2:Timer创建的线程没有处理异常,因此一旦抛出非受检异常,该线程会立即终止。

二。 用ScheduledThreadPoolExecutor代替传统的Timer

JDK 5.0以后推荐使用ScheduledThreadPoolExecutor。该类属于Executor Framework,它除了能处理异常外,还可以创建多个线程解决上面的问题。

ScheduledThreadPoolExecutor是ThreadPoolExecutor的子类;

ThreadPoolExecutor,它可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于 Timer。

一旦启用已延迟的任务就执行它,但是有关何时启用,启用后何时执行则没有任何实时保证。按照提交的先进先出 (FIFO) 顺序来启用那些被安排在同一执行时间的任务。

以下为测试代码:

package cn.iigrowing.jobs.web.action;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TaskTest {
	static 
阅读全文

童话尤克里里

  categories:儿童作品  author:

彩铅画, 漂亮的尤克里里

 

 … 阅读全文

非阻塞算法在并发容器中的实现

  categories:资料  author:

非阻塞算法在 Java 中的应用越来越广泛 , ConcurrentLinkedQueue 是 java. concurrent 包中基于非阻塞算法实现的并发容器的典范。通过本文,您将了解非阻塞算法的工作原理及其在 ConcurrentLinkedQueue 中的具体实现机制。

简介

非阻塞算法在更细粒度的层面协调争用,它比传统的锁有更高的并发性。随着非阻塞算法在 Java 中的应用越来越广泛,java.concurrent 包中用非阻塞算法实现的并发容器也越来越多,ConcurrentLinkedQueue 就是其中的一个重要成员。鉴于 ConcurrentLinkedQueue 的非阻塞算法实现在并发容器中具有代表性,本文将结合 JDK Update23 的源代码来分析它在当前的实现。由于非阻塞算法本身比较复杂,阅读本文的读者需要对 CAS 原子指令和非阻塞同步机制有所了解。本文分为两部分,第一部分主要是对非阻塞算法相关理论知识的简介,第二部分结合 ConcurrentLinkedQueue 的源代码,来探索非阻塞算法的具体实现。希望通过本文,能够有助于读者理解非阻塞算法在并发容器中的工作原理与具体实现机制。

非阻塞算法相关技术简介

为了便于读者更好的理解本文,首先让我们来对非阻塞算法相关的理论知识做个简单的了解,更详细的论述请参阅文中提及的相关参考文献。

Java 的多线程同步机制

在现代的多处理器系统中,提高程序的并行执行能力是有效利用 CPU 资源的关键。为了有效协调多线程间的并发访问,必须采用适当的同步机制来协调竞争。当前常用的多线程同步机制可以分为下面三种类型:

  • volatile 变量:轻量级多线程同步机制,不会引起上下文切换和线程调度。仅提供内存可见性保证,不提供原子性。
  • CAS 原子指令:轻量级多线程同步机制,不会引起上下文切换和线程调度。它同时提供内存可见性和原子化更新保证。
  • 内部锁和显式锁:重量级多线程同步机制,可能会引起上下文切换和线程调度,它同时提供内存可见性和原子性。

多处理器系统对并发的支持

阅读全文

用AtomicStampedReference解决cas的ABA问题

  categories:java资料  author:

来源:http://hustpawpaw.blog.163.com/blog/static/184228324201210811243127/

AtomicStampedReference解决ABA问题

在运用CAS做Lock-Free操作中有一个经典的ABA问题:

线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然为A,所以CAS成功。但实际上这时的现场已经和最初不同了,尽管CAS成功,但可能存在潜藏的问题,例如下面的例子:

cas0001

现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道A.next为B,然后希望用CAS将栈顶替换为B:

head.compareAndSet(A,B);

在T1执行上面这条指令之前,线程T2介入,将A、B出栈,再pushD、C、A,此时堆栈结构如下图,而对象B此时处于游离状态:

cas0002

此时轮到线程T1执行CAS操作,检测发现栈顶仍为A,所以CAS成功,栈顶变为B,但实际上B.next为null,所以此时的情况变为:

cas0003

其中堆栈中只有B一个元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。

以 上就是由于ABA问题带来的隐患,各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题,在Java 中,AtomicStampedReference<E>也实现了这个作用,它通过包装[E,Integer]的元组来对对象标记版本戳 stamp,从而避免ABA问题,例如下面的代码分别用AtomicInteger和AtomicStampedReference来对初始值为100的 原子整型变量进行更新,AtomicInteger会成功执行CAS操作,而加上版本戳的AtomicStampedReference对于ABA问题会 执行CAS失败:

public class Test {

private static AtomicInteger atomicInt = new AtomicInteger(100);

private static AtomicStampedReference atomicStampedRef = new AtomicStampedReference(100, 0);

 

public static void main(String[] args)

阅读全文

Java多线程系列 JUC锁

  categories:java资料  author:

来源:http://www.educity.cn/develop/1242520.html

根据锁的添加到Java中的时间,Java中的锁,可以分为”同步锁“和”JUC包中的锁“。

同步锁

即通过synchronized关键字来进行同步,实现对竞争资源的互斥访问的锁。Java 1.0版本中就已经支持同步锁了。

同步锁的原理是,对于每一个对象,有且仅有一个同步锁;不同的线程能共同访问该同步锁。但是,在同一个时间点,该同步锁能且只能被一个线程获取到。这 样,获取到同步锁的线程就能进行CPU调度,从而在CPU上执行;而没有获取到同步锁的线程,必须进行等待,直到获取到同步锁之后才能继续运行。这就是, 多线程通过同步锁进行同步的原理!

关于”同步锁”的更多内容,请参考”Java锁的基础部分”的内容。

JUC包中的锁

相比同步锁,JUC包中的锁的功能更加强大,它为锁提供了一个框架,该框架允许更灵活地使用锁,只是它的用法更难罢了。

JUC包中的锁,包括:Lock接口,ReadWriteLock接口,LockSupport阻塞原语,Condition条 件,AbstractOwnableSynchronizer/AbstractQueuedSynchronizer /AbstractQueuedLongSynchronizer三个抽象类,ReentrantLock独占 锁,ReentrantReadWriteLock读写锁。由于CountDownLatch,CyclicBarrier和Semaphore也是通过 AQS来实现的;因此,我也将它们归纳到锁的框架中进行介绍。

先看看锁的框架图,如下所示

01. Lock接口

JUC包中的 Lock 接口支持那些语义不同(重入、公平等)的锁规则。所谓语义不同,是指锁可是有”公平机制的锁”、”非公平机制的锁”、”可重入的锁”等等。”公平机制”是 指”不同线程获取锁的机制是公平的”,而”非公平机制”则是指”不同线程获取锁的机制是非公平的”,”可重入的锁”是指同一个锁能够被一个线程多次获取。

02. ReadWriteLock

ReadWriteLock 接口以和Lock类似的方式定义了一些读取者可以共享而写入者独占的锁。JUC包只有一个类实现了该接口,即 ReentrantReadWriteLock,因为它适用于大部分的标准用法上下文。但程序员可以创建自己的、适用于非标准要求的实现。

03. AbstractOwnableSynchronizer/AbstractQueuedSynchronizer/AbstractQueuedLongSynchronizer… 阅读全文

从0开始学编程(19)–java流概念入门

  categories:0基础编程  author:

一个程序, 总要 同人或者同其他程序打交到, 一个同外界没有任何联系的程序是没啥必要的。

同外界进行联系,就需要有输入和输出系统。 显示器, 手机屏幕上显示的东西可以看作是输出, 你在键盘输入东西,或者在手机选择一个图标这些都可以看作一个输入。

除了这些, 你看到一个好的网页, 把他保存起来, 这个过程要写文件或者放到收藏夹, 这些都有将信息从一个地方输出到另外一个地方的过程。

总之输入就是,  外界将东西给你,  输出就是, 你把信息或者东西给外界。我就是你的程序。

可见输入和输出是非常重要的, 我们学习编程不会输入和输出是完全不行的。但是输入和输出是比较抽象, 难懂, 因此找了段别人的流的视频, 大家可以先观看, 重点是把他坚持看完,了解流的常见概念, 看完视频在多查资料, 多找些例子练习,然后在工作中和学习中不断应用,不断实践才能对流比较好的掌握。

上视频地址和密码  http://pan.baidu.com/s/1sjwl0NN    提取密码: w4gc

为了加深理解, 找了写资料放到这里供大家参考

java比较老的流的解释:

Java语言的输入输出功能是十分强大而灵活的,对于数据的输入和输出操作以“流”(stream)的方式进行。JDK提供了各种各样的“流”类,用以获取不同种类的数据,定义在包java.io中。程序中通过标准的方法输入或输出数据。

Java中的流可以从不同的角度进行分类:
按照流的方向不同:分为输入流和输出流。
按照处理数据单位的不同:分为字节流(8位)和字符流(16位)。
按照功能不同:分为节点流和处理流。
节点流:是可以从一个特定的数据源(节点)读写数据的流(例如文件,内存)。就像是一条单一的管子接到水龙头上开始放水。
处理流:是“连接”在已经存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。就像在已经接了一条管子(节点流)的基础上,又套上几个更粗,具有特殊功能的管子(处理流)对流出的水进一步的处理。

 … 阅读全文

设计不使用互斥锁的并发数据结构

  categories:资料  author:

原文:http://www.ibm.com/developerworks/cn/aix/library/au-multithreaded_structures2/index.html

本文是讨论多线程结构的两篇系列文章的第二篇,介绍关于实现基于互斥锁的并发链表的设计方法,讨论如何设计不使用互斥锁的并发数据结构。

简介

本文是本系列的最后一篇,讨论两个主题:关于实现基于互斥锁的并发链表的设计方法和设计不使用互斥锁的并发数据结构。对于后一个主题,我选择实现一个并发堆栈并解释设计这种数据结构涉及的一些问题。用 C++ 设计独立于平台的不使用互斥锁的数据结构目前还不可行,所以我选用 GCC version 4.3.4 作为编译器并在代码中使用 GCC 特有的 __sync_* 函数。如果您是 WIndows® C++ 开发人员,可以考虑使用 Interlocked* 系列函数实现相似的功能。

并发单向链表的设计方法

清单 1 给出最基本的并发单向链表接口。是不是缺少什么东西?

清单 1. 并发单向链表接口
template <typename T>
class SList { 
   private: 
       typedef struct Node { 
            T data;
            Node 
阅读全文

HTML5 服务器推送事件(Server-sent Events)实战开发

  categories:资料  author:

来源:http://www.ibm.com/developerworks/cn/web/1307_chengfu_serversentevent/

服务器推送事件(Server-sent Events)是 HTML 5 规范中的一个组成部分,可以用来从服务端实时推送数据到浏览器端。相对于与之类似的 COMET 和 WebSocket 技术来说,服务器推送事件的使用更简单,对服务器端的改动也比较小。对于某些类型的应用来说,服务器推送事件是最佳的选择。本文对服务器推送技术进行了详 细的介绍,包含浏览器端和服务器端的相应实现细节,为在实践中使用该技术提供了指南。

对于一般的 Web 应用开发,大多数开发人员并不陌生。在 Web 应用中,浏览器和服务器之间使用的是请求 / 响应的交互模式。浏览器发出请求,服务器根据收到的请求来生成相应的响应。浏览器再对收到的响应进行处理,展现给用户。响应的格式可能是 HTML、XML 或 JSON 等。随着 REST 架构风格和 AJAX 的流行,服务器更多地使用 JSON 作为响应的数据格式。Web 应用使用 XMLHttpRequest 对象来发送请求,并根据服务器端返回的数据,对页面的内容进行动态更新。通常来说,用户在页面上的操作,比如点击或移动鼠标,会触发相应的事件。由 XMLHttpRequest 对象来发出请求,得到服务器响应之后进行页面的局部更新。这种方式的不足之处在于:服务器端产生的数据变化不能及时地通知浏览器,而是需要等到下次请求发 出时才能被浏览器获取。对于某些对数据实时性要求很高的应用来说,这种延迟是不能接受的。

为了满足这类应用的需求,就需要有某种方式能够从 服务器端推送数据给浏览器,以保证服务器端的数据变化可以在第一时间通知给用户。目前常见的解决办法有不少,主要可以分成两类。这两类方法的区别在于是否 基于 HTTP 协议来实现。不使用 HTTP … 阅读全文




快乐成长 每天进步一点点      京ICP备18032580号-1