文档章节

Java并发编程中级篇(二):使用Semaphore信号量进行多个资源并发控制

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/25 17:01
字数 767
阅读 122
收藏 1

上一节中我们使用了Semaphore信号量保护共享资源,但是它只能保护一个共享资源,当我们需要同时保护多个共享资源的时候,我们只需要在创建信号量的时候使用new Semaphore(int)构造方法,传入参数是你想要保护的共享资源数目。

    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and nonfair fairness setting.
     *
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

还是PrintQueue的例子,我们把打印队列中打印机数目增加到3台,使用一个boolean[3]数组来标记打印机是否可用,同时使用3个信号量来保证这三个打印机的并发访问控制。定义一个锁来保证更改打印机状态的时候的同步控制。获取打印机资源的时候记录打印机ID,并标记打印机处于使用状态。释放打印机资源的时候,把相应ID的打印机状态置为可用。

public class PrintQueue {
    private boolean freePrinters[];
    private Lock lockPrinters;
    private Semaphore semaphore;

    public PrintQueue() {
        this.freePrinters = new boolean[3];
        this.lockPrinters = new ReentrantLock();
        this.semaphore = new Semaphore(3);

        for (int i = 0; i < 3; i++) {
            this.freePrinters[i] = true;
        }
    }

    public void printJob(Object object) {
        try {
            semaphore.acquire();
            int assignedPrinter = getPrinter();

            long duration = (long)(Math.random() * 10);
            System.out.printf("%s: Print a Job in printer %d duration %d seconds.\n",
                    Thread.currentThread().getName(), assignedPrinter, duration);
            TimeUnit.SECONDS.sleep(duration);

            freePrinter(assignedPrinter);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    private int getPrinter() {
        lockPrinters.lock();
        int printNo = -1;
        try {
            for (int i = 0; i < freePrinters.length; i++) {
                if (freePrinters[i]) {
                    printNo = i;
                    freePrinters[i] = false;
                    break;
                }
            }
        } finally {
            lockPrinters.unlock();
        }
        return printNo;
    }

    private void freePrinter(int printNo) {
        lockPrinters.lock();

        try {
            freePrinters[printNo] = true;
        } finally {
            lockPrinters.unlock();
        }
    }

打印Job线程类和主方法类不变

public class Job implements Runnable{
    private PrintQueue printQueue;

    public Job(PrintQueue printQueue) {
        this.printQueue = printQueue;
    }

    @Override
    public void run() {
        System.out.printf("%s: Going to print a Job.\n", Thread.currentThread().getName());
        printQueue.printJob(new Object());
        System.out.printf("%s: The Job has been printed.\n", Thread.currentThread().getName());
    }
}
public class Main {
    public static void main(String[] args) {
        PrintQueue printQueue = new PrintQueue();

        Thread[] threads = new Thread[10];
        for (int i = 1; i < 10; i++) {
            threads[i] = new Thread(new Job(printQueue));
        }

        for (int i = 1; i < 10; i++) {
            threads[i].start();
        }
    }
}

执行查看控制台日志,你可以发现每次有三个打印Job可以执行。

Thread-0: Going to print a Job.
Thread-8: Going to print a Job.
Thread-7: Going to print a Job.
Thread-6: Going to print a Job.
Thread-5: Going to print a Job.
Thread-4: Going to print a Job.
Thread-3: Going to print a Job.
Thread-2: Going to print a Job.
Thread-1: Going to print a Job.
Thread-8: Print a Job in printer 1 duration 2 seconds.
Thread-7: Print a Job in printer 2 duration 6 seconds.
Thread-0: Print a Job in printer 0 duration 2 seconds.
Thread-0: The Job has been printed.
Thread-5: Print a Job in printer 1 duration 7 seconds.
Thread-6: Print a Job in printer 0 duration 9 seconds.
Thread-8: The Job has been printed.
Thread-7: The Job has been printed.
Thread-4: Print a Job in printer 2 duration 1 seconds.
Thread-4: The Job has been printed.
Thread-3: Print a Job in printer 2 duration 6 seconds.
Thread-5: The Job has been printed.
Thread-2: Print a Job in printer 1 duration 7 seconds.
Thread-6: The Job has been printed.
Thread-1: Print a Job in printer 0 duration 2 seconds.
Thread-3: The Job has been printed.
Thread-1: The Job has been printed.
Thread-2: The Job has been printed.

 

© 著作权归作者所有

阿拉德大陆的魔法师
粉丝 27
博文 91
码字总数 83019
作品 0
西城
程序员
私信 提问
Dubbo源码之服务端并发控制——ExecuteLimitFilter

上一篇关于《Dubbo客户端并发控制——ActiveLimitFilter》 作用,设计原理,及配置方式。 这篇是关于Dubbo服务端Filter组件扩展 ExecuteLimitFilter ,它可以限制服务端的方法级别的并发处理...

BakerZhu
2018/08/25
540
0
4种常用Java线程锁的特点,性能比较及使用场景

多个线程同时对同一个对象进行读写操作,很容易会出现一些难以预料的问题。所以很多时候我们需要给代码块加锁,同一时刻只允许一个线程对某个对象进行操作。多线程之所以会容易引发一些难以发现...

mikechen优知
03/10
178
0
面试:Semaphore(信号量)的成长之路

2019最寒冷,面试跳槽不能等 马上就3月份了,所谓的金三银四招聘季。2019年也许是互联网最冷清的一年,很多知名的大型互联网公司都裁员过冬。当然也有一些公司还在持续招人的,比如阿里就宣称...

尹吉欢
02/25
0
0
PV操作和信号量机制实现进程同步(对多个临界资源的互斥访问)

进程同步是我们在多线程中讨论最多的一个话题,在大多数的开发语言中,他们都有自己实现进程同步的方法或者实现。但归根结底他们实现的方式都是基于操作系统的进程同步的方式。今天我们就一起...

长平狐
2012/11/12
776
0
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
723
1

没有更多内容

加载失败,请刷新页面

加载更多

观点 | 用 MySQL 数据库,到底会不会被“卡脖子”?

>作者:明溪源 **用 MySQL 数据库,到底会不会被“卡脖子”?** 在近期不明朗的贸易形势下,一些正在规划数据库选型、迁移的用户,纷纷询问我们对 MySQL 未来前景的看法。那么使用 MySQL 数据...

爱可生
29分钟前
10
0
千万级流量架构下的负载均衡解析

一、负载均衡 负载均衡算法 转发实现 二、集群下的 Session 管理 Sticky Session Session Replication Session Server 一、负载均衡 集群中的应用服务器(节点)通常被设计成无状态,用户可以...

李红欧巴
33分钟前
78
0
一元建站-基于函数计算 + wordpress 构建 serverless 网站

前言 本文旨在通过 快速部署一个 wordpress 网站到阿里云函数计算平台 这个示例来展示 serverless web 新的开发模式, 包括 FUN 工具一键初始化 NAS, 同步网站到 NAS, 一键部署等能力, 展现函...

阿里云官方博客
35分钟前
5
0
Spring Security 整合JWT(四)

一、前言 本篇文章将讲述Spring Security 简单整合JWT 处理认证授权 基本环境 spring-boot 2.1.8 mybatis-plus 2.2.0 mysql 数据库 maven项目 Spring Security入门学习可参考之前文章: Spri...

郑清
36分钟前
8
0
零基础怎么玩转可视化大屏?这个工具只需5步!

大屏可视化怎么这么火?领导天天要,业务人员、开发人员、IT页面师就得一块熬夜加班,要是不会做大屏,都不好意思说自己做报表、做IT。 也许有人会告诉你,可视化大屏可以用JS+Ecahrts编程实...

朕想上头条
38分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部