Java学习笔记--并发工具Semaphore,CountDownLatch,CyclicBarrier,Exchanger

Semaphore 实现典型的信号量
CountDownLatch 在指定数量的事件发生前一直等待
CyclicBarrier 使一组线程在一个预定义的执行点等待
Exchanger 交换两个线程的数据

1. Semaphore

信号量(Semaphore),是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源

在java中,还可以设置该信号量是否采用公平模式,如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能排在队列的头部。

JDK中定义如下:

Semaphore(int permits)Semaphore(int permits, boolean fair)//创建具有给定的许可数和给定的公平设置的Semaphore。

Semaphore当前在多线程环境下被扩放使用,操作系统的信号量是个很重要的概念,在进程控制方面都有应用。

Java并发库Semaphore 可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,

通过 acquire() 获取一个许可,如果没有就等待.

void acquire() throws InterruptedException//获得一个通行证
void acquire(int num) throws InterruptedException//获得num个通行证

而 release() 释放一个许可。

void release() //释放一个通行证
void release(int num) //释放由num指定的多个通行证

为了用一个信号量控制对资源的访问,使用该资源的每个线程在访问资源之前,必须首先调用acquire()方法

当线程结束对资源的使用后,必须调用release()方法。

Semaphore例子:

import java.util.concurrent.Semaphore;

public class SemDemo {

    public static void main(String[] args) {
        Semaphore sem = new Semaphore(1);
        new IncThread("A",sem);
        new DecThread("B",sem);
    }
}

//共享静态变量
class Shared{
    static int count = 0;
}

class IncThread implements Runnable{
    private String name;
    private Semaphore sem;    //信号量
    public IncThread(String name,Semaphore sem){
        this.name=name;
        this.sem = sem;
        new Thread(this).start();
    }

    public void run(){
        System.out.println("Starting:"+name);
        try{
            System.out.println(name+"等待信号量.");
            sem.acquire();
            System.out.println(name+"获得信号量.");

            for(int i = 0 ; i <5 ; i++){
                Shared.count++;  //修改静态变量
                System.out.println(name+" : "+Shared.count);
                Thread.sleep(10);
            }
        }catch(InterruptedException ext){
            ext.printStackTrace();
        }
        System.out.println(name+"释放信号量.");
        sem.release();
    }
}

class DecThread implements Runnable{
    private String name;
    private Semaphore sem;
    public DecThread(String name,Semaphore sem){
        this.name=name;
        this.sem = sem;

        new Thread(this).start();
    }

    public void run(){
        System.out.println("Starting:"+name);
        try{
            System.out.println(name+"等待信号量.");
            sem.acquire();
            System.out.println(name+"获得信号量.");

            for(int i = 0 ; i <5 ; i++){
                Shared.count--;  //修改静态变量
                System.out.println(name+" : "+Shared.count);
                Thread.sleep(10);
            }
        }catch(InterruptedException ext){
            ext.printStackTrace();
        }
        System.out.println(name+"释放信号量.");
        sem.release();
    }
}

结果:

Starting:A
A等待信号量.
A获得信号量.
A : 1
Starting:B
B等待信号量.
A : 2
A : 3
A : 4
A : 5
A释放信号量.
B获得信号量.
B : 4
B : 3
B : 2
B : 1
B : 0
B释放信号量.

可见,先递增5次再递减5次,递增递减不会混在一起。

如果不使用信号量,两个线程对Shared.count的访问可能会同步发生,递增与递减可能混在一起。

2. CountDownLatch

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

主要方法

 public CountDownLatch(int count);
 public void countDown();
 public void await() throws InterruptedException
 public void await(long wait, TimeUnit tu) throws InterruptedException 

构造方法参数指定了计数的次数,指定锁存器打开前必须发生的时间数码

countDown方法,当前线程调用此方法,则计数减一

await方法,调用此方法会一直阻塞当前线程,直到计时器的值为0。

第二种形式只在wait所指定的期间内等待。wait的单位由tu指定,它是一个TimeUnit枚举的一个对象

例子:

import java.util.concurrent.CountDownLatch;

public class CDLDemo {

    public static void main(String[] args) {
        CountDownLatch cd1 = new CountDownLatch(5);
        System.out.println("Starting!");
        MyThread mt1 = new MyThread (cd1);
        new Thread(mt1).start();//启动线程
        try{
            cd1.await(); //等待锁存器打开,如果注释掉这部分,则done会出现在前面
        }catch(InterruptedException exc){
            exc.printStackTrace();
        }
        System.out.println("Done!");

    }
}
class MyThread implements Runnable{
    CountDownLatch latch;
    public MyThread(CountDownLatch latch){
        this.latch=latch;
        //new Thread(this).start();
    }

    public void run(){
        for(int i = 0 ; i < 5 ; i ++){
            System.out.println("第"+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            latch.countDown();
        }
    }
}

结果:


未注释await()

等到计数为4时再打开锁存器

done


注释掉await()

不等待锁存器打开

Starting!
第0
第1
第2
第3
第4
Done!

Starting!
Done!
第0
第1
第2
第3
第4

3. CyclicBarrier

时间: 2024-10-03 02:36:56

Java学习笔记--并发工具Semaphore,CountDownLatch,CyclicBarrier,Exchanger的相关文章

非专业码农 JAVA学习笔记 6java工具类和算法-string

续<非专业码农 JAVA学习笔记 5 java工具类和算法> 五.字符串string 字符串和字符的差别:字符串双引号括起来”n”,字符用单引号括起来,表示一种符号’\n’ 1.string的主要方法和属性 类 方法或者属性 备注 定义string Stirng s=new string(“值”),string s=”值” 属性 string.length:string的长度为字节 方法startswith,endswith s.startwith(“值”)-以值为开头,s.endswith(

Java并发工具类 - CountDownLatch

Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html 官方API. CountDownLatch能够使一个或多个线程等待其他线程完成各自的工作后再执行:CountDownLatch是JDK 5+里面

java学习笔记 第二篇 核心技术(二)

第十四章 集合类 集合类用来存放对象的引用.继承关系如下图: 14.1 Collection 接口 是层次结构中的根接口,构成Collection的单位称为元素.Collection接口不能直接使用,但该接口提供了添加元素.删除元素.管理数据的方法. Collection接口常用方法: 14.2 List 集合 包括List接口以及List集合的所有实现类.List集合中的元素允许重复,各元素循序就是对象插入的顺序 1.List接口,两个重要方法: get(int index): 获取指定索引位

Java学习笔记_25_Collections类

25.Collections类: Collections类是一个工具类,用来对集合进行操作,它主要是提供一些排序算法,包括随机排序.反相排序等. Collections类提供了一些静态方法,实现了基于List容器的一些常用算法. Collections的一些方法列表: · void sort(List): 对List内的元素进行排序. · void shuffle(List): 对List内的元素随机排序. · void reverse(List): 对List内的元素进行逆序排列. · voi

java学习笔记14--多线程编程基础1

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为一个进程,例如:用字处理软件编辑文稿时,同时打开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程 进程要占用相当一部分处理器时间和内存资源 进程具有独立的内存空间 通信很不方便,编程模型比较复杂 多线程 一个程序中多段代码同时并发执行,称为多线程,线程比进程开销小,协作和数据交换容易

Java学习笔记3-操作符

Java基本操作符:+.-.*./.%.=.==.!=.+=.-=. 优先级:先乘除后加减,如果是连接符+号会优先往前匹配,比如 a+++++b,会被解释称 a++ ++ +b,所以会报错,需要自行使用括号隔离为 (a++) + (++b). 对象的引用如果赋值给了对象的引用后,2 个对象将指向同一个引用,有一个对象的引用重新赋值后将同时影响到另一个对象,比如 ClassName classA = new ClassName(); ClassName classB = new ClassName

java学习笔记10--泛型总结

java学习笔记系列: java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3--类与对象的基础 java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址:http://www.cnblogs.com/archimedes/p/java-study-note10.html,转载

Java学习笔记心得——初识Java

初识Java 拿到这本厚厚的<Java学习笔记>,翻开目录:Java平台概论.从JDK到TDE.认识对象.封装.继承与多态...看着这些似懂非懂的术语名词,心里怀着些好奇与担忧,就这样我开始走进Java的世界.  Java产生的历史 Java来自于Sun公司的一个叫Green Project中撰写的程序语言,全球信息网(World Wide Web)兴起,Java Applet成为网页互动技术的代表,特别适合于Internet应用程序开发. Java语言的特点 1.面向对象 这是Java最重要

java学习笔记8--接口总结

接着前面的学习: java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3--类与对象的基础 java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址:http://www.cnblogs.com/archimedes/p/java-study-note8.html,转载请注明源地址. 生活中的接口: 什么是接口? 一个Java接口是一些方法特