欢迎访问欧博亚洲(Allbet Game)!

首页科技正文

邢台酒店:并发工具类——Semaphore

admin2020-05-123

本博客系列是学习并发编程过程中的纪录总结。由于文章对照多,写的时间也对照散,以是我整理了个目录贴(传送门),利便查阅。

并发编程系列博客传送门

Semaphore([' seməf :(r)])的主要作用是控制线程并发的数目。我们可以将Semaphore想象成景区的一个门卫,这个门卫卖力发放景区入园的允许证。

景区为了游客的入园鉴赏体验,决议最多允许200个有个同时在园内鉴赏。那么这个门卫在天天开园的时刻手中都会有200张允许证,每当一个游客要入园的时刻门卫会给游客发放一张允许证,当门卫手中的允许证发完之后再有游客需要入园的话就必须守候。

当游客鉴赏完毕之后,出园的时刻需要将允许证交还到门卫手上。门卫将这些交还的允许证再发守候的游客,这些游客就能顺遂入园了。

Semaphore的API简介

Semaphore的API使用起来也对照简朴,常见的API简介如下:

  • Semaphore(int permits):组织方式,建立具有给定允许数的计数信号量并设置为非公正信号量。
  • Semaphore(int permits,boolean fair):组织方式,当fair即是true时,建立具有给定允许数的计数信号量并设置为公正信号量。
  • void acquire():今后信号量获取一个允许前线程将一直壅闭。相当于一辆车占了一个车位。
  • void acquire(int n):今后信号量获取给定数目允许,在提供这些允许前一直将线程壅闭。好比n=2,就相当于一辆车占了两个车位。
  • boolean tryAcquire(int permits, long timeout, TimeUnit unit):实验获取,在给定的时间内没获取到资源超时
  • void release():释放一个允许,将其返回给信号量。就如同车开走返回一个车位。
  • void release(int n):释放n个允许。
  • int availablePermits():当前可用的允许数。

Semaphore的常见用法

下面给出一个Oracle官方文档中的列子代码:

class Pool {
    // 可同时接见资源的最大线程数
    private static final int MAX_AVAILABLE = 100; 
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
    // 共享资源
    protected Object[] items = new Object[MAX_AVAILABLE];   
    protected boolean[] used = new boolean[MAX_AVAILABLE];
    public Object getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }
    public void putItem(Object x) {
        if (markAsUnused(x))
            available.release();
    }
    private synchronized Object getNextAvailableItem() {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }
    private synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else
                    return false;
            }
        }
        return false;
    }
}

items数组可以看成是我们的共享资源,当有线程实验使用共享资源时,我们要求线程先获得“允许”(挪用Semaphoreacquire方式),这样线程就拥有了权限,否则就需要守候。当使用完资源后,线程需要挪用Semaphorerelease方式释放允许。

Semaphore并不能替换synchronized

有些书中提到:若是将Semaphore的允许证数目设置成1的话,就能实现synchronized的功效。实在这种说法是纰谬的。

下面使用Semaphore来控制对一个账户举行并发存钱和取钱的动作,若是Semaphore能实现synchronized的功效的话,账户最后的余额应该照样10000,但代码执行后的效果并不是这样。人人可以执行下面的代码看下效果。

public static final int THREAD_COUNT = 100;

    public static void main(String[] args) {
        BankAccount myAccount = new BankAccount("accountOfMG", 10000.00);
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        int var = new Random().nextInt(100);
                        Thread.sleep(var);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    double deposit = myAccount.deposit(1000.00);
                    System.out.println(Thread.currentThread().getName() + " balance1:" + deposit);
                }
            }).start();
        }
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        int var = new Random().nextInt(100);
                        Thread.sleep(var);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    double deposit = myAccount.withdraw(1000.00);
                    System.out.println(Thread.currentThread().getName() + " balance2:" + deposit);

                }
            }).start();
        }
    }

    private static class BankAccount {

        Semaphore semaphore = new Semaphore(1);

        String accountName;
        double balance;

        public BankAccount(String accountName, double balance) {
                this.accountName = accountName;
                this.balance = balance;
        }

        public double deposit(double amount) {
            try {
                semaphore.acquire();
                balance = balance + amount;
                return balance;
            } catch (Exception e) {
                throw new RuntimeException("中止...");
            } finally {
                semaphore.release();
            }
        }

        public double withdraw(double amount) {
            try {
                semaphore.acquire();
            balance = balance - amount;
            return balance;
            } catch (Exception e) {
                throw new RuntimeException("中止...");
            } finally {
                semaphore.release();
            }
        }

    }

这里Semaphore并不能实现synchronized的功效的原因是:Semaphore并不能保证共享变量的可见性。

实现原理

Semaphore底层原理照样基于AQS机制的。这边就不具体分析了,感兴趣的可以参考我前面关于AQS的文章。

简朴总结

  • Semaphore只能用来做线程同步——控制线程的执行顺序,然则并不能保证线程平安;
  • Semaphore主要用来控制线程的并发数目,通常用在限流组件中。
  • Semaphore基于AQS机制实现。
,

申博Sunbet

申博Sunbet www.cdzmxslvs.com Sunbet是申博娱乐的官方网站。Sunbt官网有你喜欢的Sunbet、申博APP下载、申博娱乐最新网址、申博娱乐网最新网址等。

转载声明:本站发布文章及版权归原作者所有,转载本站文章请注明文章来源:欧博亚洲(Allbet Game)!

本文链接:https://www.qzkaishanjx.com/post/784.html

网友评论