Semaphore的使用

Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

Semaphore的主要方法摘要:

  void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。

  void release():释放一个许可,将其返回给信号量。

  int availablePermits():返回此信号量中当前可用的许可数。

  boolean hasQueuedThreads():查询是否有线程正在等待获取。

下面是一个例子:

实例1

package com.paincupid.springmvc.application.concurrent;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final Semaphore sp = new Semaphore(3);// 创建Semaphore信号量,初始化许可大小为3
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e2) {
                e2.printStackTrace();
            }
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        sp.acquire();// 请求获得许可,如果有可获得的许可则继续往下执行,许可数减1。否则进入阻塞状态
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + "进入,当前已有" + (3 - sp.availablePermits()) + "个并发");
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + "即将离开");
                    sp.release();// 释放许可,许可数加1
                    // 下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
                    System.out.println("线程" + Thread.currentThread().getName() + "已离开,当前已有" + (3 - sp.availablePermits()) + "个并发");
                }
            };
            service.execute(runnable);
        }
    }

}

结果

线程pool-1-thread-1进入,当前已有1个并发
线程pool-1-thread-2进入,当前已有2个并发
线程pool-1-thread-3进入,当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-4进入,当前已有3个并发
线程pool-1-thread-2已离开,当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-5进入,当前已有3个并发
线程pool-1-thread-1已离开,当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-4已离开,当前已有2个并发
线程pool-1-thread-6进入,当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-7进入,当前已有3个并发
线程pool-1-thread-3已离开,当前已有3个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-6已离开,当前已有2个并发
线程pool-1-thread-8进入,当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-5已离开,当前已有3个并发
线程pool-1-thread-9进入,当前已有3个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-10进入,当前已有3个并发
线程pool-1-thread-9已离开,当前已有3个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开,当前已有2个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-8已离开,当前已有1个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开,当前已有0个并发

实例2

package com.paincupid.springmvc.application.concurrent;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
 */

public class SemaphoreLockTest {

    public static void main(String[] args) {
        final Business business = new Business();
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 3; i++) {
            executor.execute(new Runnable() {
                public void run() {
                    business.service();
                }
            }

            );
        }
        executor.shutdown();
    }

    private static class Business {
        private int count;
        Lock lock = new ReentrantLock();
        Semaphore sp = new Semaphore(1);

        public void service() {
            // lock.lock();
            try {
                sp.acquire(); // 当前线程使用count变量的时候将其锁住,不允许其他线程访问
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            try {
                count++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(count);
            } catch (RuntimeException e) {
                e.printStackTrace();
            } finally {
                // lock.unlock();
                sp.release(); // 释放锁
            }
        }
    }

}

结果

1
2
3

实例3

使用Semaphore实现简单的阻塞队列 @Description: @param @param args

package com.paincupid.springmvc.application.concurrent;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

public class SemaphoreBlockingQueue {

    /**
     * @Title: 使用Semaphore实现简单的阻塞队列 @Description: @param @param args
     * 设定文件 @return void 返回类型 @throws
     */
    public static void main(String[] args) {
        SemaphoreQueue queue = new SemaphoreQueue(20);
        // 开始生产
        Productor productor = new Productor(queue);
        productor.setName("生产者");
        productor.start();
        // 开始消费
        Cousumertor c1 = new Cousumertor(queue);
        c1.setName("消费者-c1");
        Cousumertor c2 = new Cousumertor(queue);
        c2.setName("消费者-c2");
        c1.start();
        c2.start();
    }

}

/**
 * 队列 mutex相当于锁,用于控制非线程安全的valueList的操作
 */
class SemaphoreQueue {
    private List<Integer> valueList;
    private Semaphore putActionNum;// 可以进行put操作的许可数量
    private Semaphore getActionNum;// 可以进行take操作的许可数量
    private Semaphore mutex;

    public SemaphoreQueue(int capacity) {
        putActionNum = new Semaphore(capacity);// 维护队列大小
        getActionNum = new Semaphore(0);// 初始化时,队列为空,put操作许可数量为0
        mutex = new Semaphore(1);// 用于保护非线程安全的valueList操作,用于并发生产时控制
        valueList = new ArrayList<Integer>(capacity);
    }

    public void put(Integer message) {
        try {
            putActionNum.acquire();// put操作许可减1
            mutex.acquire();
            valueList.add(message);
            mutex.release();
            getActionNum.release();// get操作许可加1
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public Integer take() {
        Integer message = null;
        try {
            getActionNum.acquire();// get操作许可减1
            mutex.acquire();
            if (valueList.size() > 0) {
                message = valueList.get(0);
                valueList.remove(0);
            } else {
                return null;
            }
            mutex.release();
            putActionNum.release();// put操作许可加1
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return message;
    }
}

/**
 * 生产者
 */
class Productor extends Thread {
    SemaphoreQueue queue;

    public Productor(SemaphoreQueue queue) {
        this.queue = queue;
    }

    @SuppressWarnings("static-access")
    public void run() {
        int i = 0;
        try {
            while (true) {
                i++;
                Integer message = new Integer(i);
                queue.put(message);
                if (i % 20 == 0) {
                    System.out.println("======== " + this.getName() + " 累计生产了 " + i + " 条消息  =======");
                    Thread.currentThread().sleep(1000);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * 消费者
 */
class Cousumertor extends Thread {
    SemaphoreQueue queue;

    public Cousumertor(SemaphoreQueue queue) {
        this.queue = queue;
    }

    @SuppressWarnings("static-access")
    public void run() {
        try {
            while (true) {
                Integer message = queue.take();
                if (message != null) {
                    System.out.println("======== " + this.getName() + " 消费消息:" + message + " =======");
                }
                Thread.currentThread().sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果

======== 生产者 累计生产了 20 条消息 =======
======== 消费者-c1 消费消息:1 =======
======== 消费者-c2 消费消息:2 =======
======== 消费者-c2 消费消息:3 =======
======== 消费者-c1 消费消息:4 =======
======== 消费者-c1 消费消息:5 =======
======== 消费者-c2 消费消息:6 =======
======== 消费者-c1 消费消息:7 =======
======== 消费者-c2 消费消息:8 =======
======== 消费者-c2 消费消息:9 =======
======== 消费者-c1 消费消息:10 =======
======== 消费者-c2 消费消息:11 =======
======== 消费者-c1 消费消息:12 =======
======== 消费者-c1 消费消息:13 =======
======== 消费者-c2 消费消息:14 =======
======== 消费者-c2 消费消息:15 =======
======== 消费者-c1 消费消息:16 =======
======== 消费者-c2 消费消息:17 =======
======== 消费者-c1 消费消息:18 =======
======== 消费者-c1 消费消息:19 =======
======== 消费者-c2 消费消息:20 =======
======== 生产者 累计生产了 40 条消息 =======
======== 消费者-c2 消费消息:21 =======
======== 消费者-c1 消费消息:22 =======
======== 消费者-c1 消费消息:23 =======
======== 消费者-c2 消费消息:24 =======
======== 消费者-c1 消费消息:25 =======
======== 消费者-c2 消费消息:26 =======
======== 消费者-c1 消费消息:27 =======
======== 消费者-c2 消费消息:28 =======
======== 消费者-c2 消费消息:29 =======
======== 消费者-c1 消费消息:30 =======
======== 消费者-c2 消费消息:31 =======
======== 消费者-c1 消费消息:32 =======
======== 消费者-c2 消费消息:33 =======
======== 消费者-c1 消费消息:34 =======
======== 消费者-c1 消费消息:35 =======
======== 消费者-c2 消费消息:36 =======
======== 消费者-c1 消费消息:37 =======
======== 消费者-c2 消费消息:38 =======
======== 消费者-c2 消费消息:39 =======
======== 消费者-c1 消费消息:40 =======
======== 生产者 累计生产了 60 条消息 =======
======== 消费者-c2 消费消息:41 =======
======== 消费者-c1 消费消息:42 =======
======== 消费者-c2 消费消息:43 =======
======== 消费者-c1 消费消息:44 =======
======== 消费者-c2 消费消息:45 =======
======== 消费者-c1 消费消息:46 =======
======== 消费者-c2 消费消息:47 =======
======== 消费者-c1 消费消息:48 =======
======== 消费者-c2 消费消息:49 =======
======== 消费者-c1 消费消息:50 =======
======== 消费者-c2 消费消息:51 =======
======== 消费者-c1 消费消息:52 =======
======== 消费者-c1 消费消息:53 =======
======== 消费者-c2 消费消息:54 =======
======== 消费者-c2 消费消息:55 =======
======== 消费者-c1 消费消息:56 =======
======== 消费者-c2 消费消息:57 =======
======== 消费者-c1 消费消息:58 =======
======== 消费者-c2 消费消息:59 =======
======== 消费者-c1 消费消息:60 =======
======== 生产者 累计生产了 80 条消息 =======
======== 消费者-c2 消费消息:61 =======
======== 消费者-c1 消费消息:62 =======
======== 消费者-c1 消费消息:63 =======
======== 消费者-c2 消费消息:64 =======
======== 消费者-c2 消费消息:65 =======
======== 消费者-c1 消费消息:66 =======
======== 消费者-c2 消费消息:67 =======
======== 消费者-c1 消费消息:68 =======
======== 消费者-c1 消费消息:69 =======
======== 消费者-c2 消费消息:70 =======
======== 消费者-c2 消费消息:71 =======
======== 消费者-c1 消费消息:72 =======
======== 消费者-c2 消费消息:73 =======
======== 消费者-c1 消费消息:74 =======
======== 消费者-c1 消费消息:75 =======
======== 消费者-c2 消费消息:76 =======
======== 消费者-c1 消费消息:77 =======
======== 消费者-c2 消费消息:78 =======
======== 消费者-c2 消费消息:79 =======
======== 消费者-c1 消费消息:80 =======
======== 生产者 累计生产了 100 条消息 =======
======== 消费者-c1 消费消息:81 =======
======== 消费者-c2 消费消息:82 =======
======== 消费者-c1 消费消息:83 =======

转自:http://www.cnblogs.com/liuling/p/2013-8-20-03.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值