码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-04-02 22:25:53      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:

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

 

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

标签:

原文地址:http://www.cnblogs.com/gnivor/p/4388273.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!