资讯专栏INFORMATION COLUMN

Java多线程工具箱之Semaphore

FleyX / 756人阅读

摘要:多线程工具箱之前言这一篇谈一下信号量。信息信息信息信息信息信息信息信息信息信息信息小结适用于多线程请求数量资源的场景,但无法解决单多个线程对同一资源访问的竞争性访问。在后面我们在我们的多线程工具箱里面陆续会提到。

Java多线程工具箱之Semaphore 前言

这一篇谈一下Semaphore:信号量。

将Semaphore类比为为信号灯,被继承Runable的线程类比为列车:理解信号量可以参考控制列车的信号灯:铁道上有多个列车,由信号灯通知其可用情况。若列车拿到的信号灯为绿灯,列车可以通过,否则列车不能通过。

Semaphore用于限制访问线程多于可用资源的场景。

1.1 基本API 构造器 Semaphore(int premits)

构造传入初始化的允许数量。

方法 acquire()

请求允许,未有有效的允许或者中断之前,线程将会阻塞。

方法 release()

释放允许。

1.2 范例

在范例中,我们使用一个机场请求跑道的模拟程序,机场有3个跑道,这个时段降落的航班一共有10个。由于跑道远没有飞机的数量多,因此需要飞机需要等待可用的跑道资源。这个程序就是模拟了这个过程。

UML

App.java
import java.util.Random;

import lombok.extern.java.Log;

@Log
public class App {

    static Random ran = new Random(System.currentTimeMillis());

    public static void main(String[] args) {
        Airport ap = new Airport("Baiyun Airport", 3);
        for (int index = 0; index < 10; index++) {

            AirPlane plane = new AirPlane(index, String.valueOf(index), String.valueOf(index), ap,
                    ran.nextInt(2) == 0 ? Action.landing : Action.takeOff);
            Thread thread = new Thread(plane);
            thread.start();
        }
    }

}

Airport.java
import java.util.Arrays;
import java.util.concurrent.Semaphore;

import lombok.Data;
import lombok.extern.java.Log;

@Log
@Data
public class Airport {

    private String name;
    private Semaphore semaphore;
    private Runway[] runways;

    public Airport(String name, int numberOfRunway) {

        this.name = name;
        this.semaphore = new Semaphore(numberOfRunway);
        runways = new Runway[numberOfRunway];

        for (int index = 0; index < numberOfRunway; index++) {
            Runway currentRunway = new Runway(name, index);

            runways[index] = currentRunway;
        }

        log.info("Airpot is ready :" + Arrays.toString(runways));

    }

    public Runway requestRunway() throws InterruptedException {
        semaphore.acquire();

        while (true) {
            for (int index = 0; index < runways.length; index++) {
                Runway runway = runways[index];
                if (!runway.isInUse()) {
                    runway.setInUse(true);
                    return runway;
                }
            }
            log.warning("all runway is using, and wait till there is runay release.");
        }
    }

    public void releaseRunway(Runway release) {

        for (int index = 0; index < runways.length; index++) {
            Runway runway = runways[index];
            if (runway.equals(release)) {
                runway.setInUse(false);
                semaphore.release();
            }
        }

    }

}
Airplane.java
import java.util.Random;

import lombok.Data;
import lombok.extern.java.Log;

@Data
@Log
public class AirPlane implements Runnable {

    private int id;
    private String name;
    private String company;
    private Airport airport;
    private Action action;
    private static Random rand = new Random(System.currentTimeMillis());

    public AirPlane(int id, String name, String company, Airport airport, Action action) {
        this.id = id;
        this.name = name;
        this.company = company;
        this.airport = airport;
        this.action = action;
    }

    @Override
    public void run() {

        Runway runway = null;

        try {
            runway = airport.requestRunway();

            log.info(this.toString() + "is using " + runway.toString() + " to " + this.action);

            int sleepSecond = rand.nextInt(10) * 1000;

            Thread.sleep(sleepSecond);

        } catch (InterruptedException e) {
            log.warning("request runway error");
            e.printStackTrace();
        } finally {

            if (airport != null && runway != null) {
                airport.releaseRunway(runway);
            }
        }

    }

}
Runway.java
import lombok.Data;

@Data
public class Runway {

    private String name;
    private boolean inUse = false;

    public Runway(String airportName, int runwayIndex) {
        this.name = airportName + "_" + runwayIndex;
    }

}

运行结果

可以从运行结果中看到,程序运行的第一秒,首先几架的飞机(线程)都第一时间的获得了跑道(资源),而后面几架飞机(线程),则在前面的飞机退出(sleep)跑道(资源)后获得使用权,进行起飞或降落。


Aug 13, 2018 12:56:32 AM online.tangbk.thread.study.semaphore.Airport 
信息: Airpot is ready :[Runway(name=Baiyun Airport_0, inUse=false), Runway(name=Baiyun Airport_1, inUse=false), Runway(name=Baiyun Airport_2, inUse=false)]
Aug 13, 2018 12:56:33 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=1, name=1, company=1, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 1], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=false)]), action=landing)is using Runway(name=Baiyun Airport_1, inUse=true) to landing
Aug 13, 2018 12:56:33 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=2, name=2, company=2, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=takeOff)is using Runway(name=Baiyun Airport_2, inUse=true) to takeOff
Aug 13, 2018 12:56:33 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=0, name=0, company=0, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 2], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=false), Runway(name=Baiyun Airport_2, inUse=false)]), action=landing)is using Runway(name=Baiyun Airport_0, inUse=true) to landing
Aug 13, 2018 12:56:33 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=8, name=8, company=8, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=takeOff)is using Runway(name=Baiyun Airport_1, inUse=true) to takeOff
Aug 13, 2018 12:56:35 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=3, name=3, company=3, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=takeOff)is using Runway(name=Baiyun Airport_0, inUse=true) to takeOff
Aug 13, 2018 12:56:37 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=4, name=4, company=4, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=landing)is using Runway(name=Baiyun Airport_2, inUse=true) to landing
Aug 13, 2018 12:56:40 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=5, name=5, company=5, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=landing)is using Runway(name=Baiyun Airport_2, inUse=true) to landing
Aug 13, 2018 12:56:40 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=6, name=6, company=6, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=landing)is using Runway(name=Baiyun Airport_2, inUse=true) to landing
Aug 13, 2018 12:56:41 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=7, name=7, company=7, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=takeOff)is using Runway(name=Baiyun Airport_1, inUse=true) to takeOff
Aug 13, 2018 12:56:41 AM online.tangbk.thread.study.semaphore.AirPlane run
信息: AirPlane(id=9, name=9, company=9, airport=Airport(name=Baiyun Airport, semaphore=java.util.concurrent.Semaphore@61a09c6b[Permits = 0], runways=[Runway(name=Baiyun Airport_0, inUse=true), Runway(name=Baiyun Airport_1, inUse=true), Runway(name=Baiyun Airport_2, inUse=true)]), action=landing)is using Runway(name=Baiyun Airport_0, inUse=true) to landing

1.3 Semaphore小结

Semaphore适用于多线程请求数量资源的场景,但无法解决单多个线程对同一资源访问的竞争性访问。对于单一资源的竞争性访问,依然要使用synchronize关键字或atomic等甚至ReadWriteLock关键字或工具类进行限制。
在后面我们在我们的多线程工具箱里面陆续会提到。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76733.html

相关文章

  • Java线程进阶(二十)—— J.U.Csynchronizer框架:Semaphore

    摘要:当线程使用完共享资源后,可以归还许可,以供其它需要的线程使用。所以,并不会阻塞调用线程。立即减少指定数目的可用许可数。方法用于将可用许可数清零,并返回清零前的许可数六的类接口声明类声明构造器接口声明 showImg(https://segmentfault.com/img/bVbfdnC?w=1920&h=1200); 本文首发于一世流云的专栏:https://segmentfault...

    boredream 评论0 收藏0
  • Java线程进阶(一)—— J.U.C并发包概述

    摘要:整个包,按照功能可以大致划分如下锁框架原子类框架同步器框架集合框架执行器框架本系列将按上述顺序分析,分析所基于的源码为。后,根据一系列常见的多线程设计模式,设计了并发包,其中包下提供了一系列基础的锁工具,用以对等进行补充增强。 showImg(https://segmentfault.com/img/remote/1460000016012623); 本文首发于一世流云专栏:https...

    anonymoussf 评论0 收藏0
  • (八)java线程Semaphore

    摘要:在每个线程获取之前,必须先从信号量获取许可。注意,因为同时可能发生取消,所以返回并不保证有其他线程等待获取许可。该值仅是估计的数字,因为在此方法遍历内部数据结构的同时,线程的数目可能动态地变化。 本人邮箱: 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kcogithub: https://github.com/kco1989/kco代码已经全部托...

    DesGemini 评论0 收藏0
  • Java线程打辅助的三个小伙子

    摘要:前言之前学多线程的时候没有学习线程的同步工具类辅助类。而其它线程完成自己的操作后,调用使计数器减。信号量控制一组线程同时执行。 前言 之前学多线程的时候没有学习线程的同步工具类(辅助类)。ps:当时觉得暂时用不上,认为是挺高深的知识点就没去管了.. 在前几天,朋友发了一篇比较好的Semaphore文章过来,然后在浏览博客的时候又发现面试还会考,那还是挺重要的知识点。于是花了点时间去了解...

    pingink 评论0 收藏0
  • Java线程进阶(五)—— J.U.Clocks框架:LockSupport

    摘要:初始时,为,当调用方法时,线程的加,当调用方法时,如果为,则调用线程进入阻塞状态。该对象一般供监视诊断工具确定线程受阻塞的原因时使用。 showImg(https://segmentfault.com/img/remote/1460000016012503); 本文首发于一世流云的专栏:https://segmentfault.com/blog... 一、LockSupport类简介...

    jsyzchen 评论0 收藏0

发表评论

0条评论

阅读需要支付1元查看
<