• JAVA线程同步 (三)信号量


    一个信号量有且仅有3种操作,且它们全部是原子的:初始化、增加和减少 
    增加可以为一个进程解除阻塞; 
    减少可以让一个进程进入阻塞。

    信号量维护一个许可集,若有必要,会在获得许可之前阻塞每一个线程: 
              //从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。 
              acquireUninterruptibly(int permits){} 
    每一个release()添加一个许可,从而可能释放一个正在阻塞的获取者。 
    Semaphore只对可用许可的号码进行计数,并采取相应的行动。 
      
    如何获得Semaphore对象? 
        public Semaphore(int permits,boolean fair) 
        permits:初始化可用的许可数目。 
        fair: 若该信号量保证在征用时按FIFO的顺序授予许可,则为true,否则为false; 
        
    如何从信号量获得许可? 
        public void acquire() throws InterruptedException

    如何释放一个许可,并返回信号量? 
        public void release() 
        
    代码实例: 
        20个人去银行存款,但是该银行只有两个办公柜台,有空位则上去存钱,没有空位则只能去排队等待

    复制代码
    package com.xhj.thread;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Semaphore;
    
    /**
     * 线程信号量Semaphore的运用
     * 
     * @author XIEHEJUN
     * 
     */
    public class SemaphoreThread {
        private int a = 0;
    
        /**
         * 银行存钱类
         */
        class Bank {
            private int account = 100;
    
            public int getAccount() {
                return account;
            }
    
            public void save(int money) {
                account += money;
            }
        }
    
        /**
         * 线程执行类,每次存10块钱
         */
        class NewThread implements Runnable {
            private Bank bank;
            private Semaphore semaphore;
    
            public NewThread(Bank bank, Semaphore semaphore) {
                this.bank = bank;
                this.semaphore = semaphore;
            }
    
            @Override
            public void run() {
                int b = a++;
                if (semaphore.availablePermits() > 0) {
                    System.out.println("线程" + b + "启动,进入银行,有位置立即去存钱");
                } else {
                    System.out.println("线程" + b + "启动,进入银行,无位置,去排队等待等待");
                }
                try {
                    semaphore.acquire();
                    bank.save(10);
                    System.out.println(b + "账户余额为:" + bank.getAccount());
                    Thread.sleep(1000);
                    System.out.println("线程" + b + "存钱完毕,离开银行");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 建立线程,调用内部类,开始存钱
         */
        public void useThread() {
            Bank bank = new Bank();
            // 定义10个新号量
            Semaphore semaphore = new Semaphore(2);
            // 建立一个缓存线程池
            ExecutorService es = Executors.newCachedThreadPool();
            // 建立20个线程
            for (int i = 0; i < 10; i++) {
                // 执行一个线程
                es.submit(new Thread(new NewThread(bank, semaphore)));
            }
            // 关闭线程池
            es.shutdown();
    
            // 从信号量中获取两个许可,并且在获得许可之前,一直将线程阻塞
            semaphore.acquireUninterruptibly(2);
            System.out.println("到点了,工作人员要吃饭了");
            // 释放两个许可,并将其返回给信号量
            semaphore.release(2);
        }
    
        public static void main(String[] args) {
            SemaphoreThread test = new SemaphoreThread();
            test.useThread();
        }
    }
    复制代码

       

    线程0启动,进入银行,有位置立即去存钱
    线程4启动,进入银行,有位置立即去存钱
    线程1启动,进入银行,有位置立即去存钱
    线程2启动,进入银行,有位置立即去存钱
    线程3启动,进入银行,有位置立即去存钱
    线程6启动,进入银行,无位置,去排队等待等待
    0账户余额为:120
    4账户余额为:120
    线程5启动,进入银行,有位置立即去存钱
    线程7启动,进入银行,无位置,去排队等待等待
    线程8启动,进入银行,无位置,去排队等待等待
    线程9启动,进入银行,无位置,去排队等待等待
    线程4存钱完毕,离开银行
    线程0存钱完毕,离开银行
    1账户余额为:130
    2账户余额为:140
    线程1存钱完毕,离开银行
    线程2存钱完毕,离开银行
    3账户余额为:150
    6账户余额为:160
    线程6存钱完毕,离开银行
    线程3存钱完毕,离开银行
    5账户余额为:170
    7账户余额为:180
    线程5存钱完毕,离开银行
    线程7存钱完毕,离开银行
    8账户余额为:190
    9账户余额为:200
    线程9存钱完毕,离开银行
    线程8存钱完毕,离开银行
    到点了,工作人员要吃饭了

    思考: 
        在很多情况下,可能有多个线程需要访问数目很少的资源。假想在服务器上运行着若干个回答客户端请求的线程。这些线程需要连接到同一数据库,但任一时刻 
        只能获得一定数目的数据库连接。你要怎样才能够有效地将这些固定数目的数据库连接分配给大量的线程? 
        
    答:1.给方法加同步锁,保证同一时刻只能有一个人去调用此方法,其他所有线程排队等待,但是此种情况下即使你的数据库链接有10个,也始终只有一个处于使

            用状态。这样将会大大的浪费系统资源,而且系统的运行效率非常的低下。


        2.另外一种方法当然是使用信号量,通过信号量许可与数据库可用连接数相同的数目,将大大的提高效率和性能。

  • 相关阅读:
    EL表达式学习
    IDEA maven项目创建速度慢
    c语言栈的链表实现
    c数据结构学习随笔
    自定义JSP中的Taglib标签之四自定义标签中的Function函数
    深入理解HTTP Session
    利用GeneratedKeyHolder获得新增数据主键值
    RBAC用户角色权限设计方案
    Fragment与Activity交互(使用接口)
    php session 自定义的设置测试
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/7220715.html
Copyright © 2020-2023  润新知