Java多线程通信方式[三]

信号量

**信号量(semaphore):**是一种用于提供不同进程之间或者一个给定的不同线程间同步手段的原语。信号量多用于进程间的同步与互斥,简单的说一下同步和互斥的意思:

同步:处理竞争就是同步,安排进程执行的先后顺序就是同步,每个进程都有一定的个先后执行顺序。

互斥:互斥访问不可共享的临界资源,同时会引发两个新的控制问题(互斥可以说是特殊的同步)。

竞争:当并发进程竞争使用同一个资源的时候,我们就称为竞争进程。

共享资源通常分为两类:一类是互斥共享资源,即任一时刻只允许一个进程访问该资源;另一类是同步共享资源,即同一时刻允许多个进程访问该资源;信号量是解决互斥共享资源的同步问题而引入的机制。

简单说一下信号量的工作机制(因为真的很简单),可以直接理解成计数器(当然其实加锁的时候肯定不能这么简单,不只只是信号量了),信号量会有初值(>0),每当有进程申请使用信号量,通过一个P操作来对信号量进行-1操作,当计数器减到0的时候就说明没有资源了,其他进程要想访问就必须等待(具体怎么等还有说法,比如忙等待或者睡眠),当该进程执行完这段工作(我们称之为临界区)之后,就会执行V操作来对信号量进行+1操作。

临界区:临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。

临界资源:只能被一个进程同时使用(不可以多个进程共享),要用到互斥。

我们可以说信号量也是进程间通信的一种方式,比如互斥锁的简单实现就是信号量,一个进程使用互斥锁,并通知(通信)其他想要该互斥锁的进程,阻止他们的访问和使用。

当有进程要求使用共享资源时,需要执行以下操作:

1.系统首先要检测该资源的信号量;

2.若该资源的信号量值大于0,则进程可以使用该资源,此时,进程将该资源的信号量值减1;

3.若该资源的信号量值为0,则进程进入休眠状态,直到信号量值大于0时进程被唤醒,访问该资源;

当进程不再使用由一个信号量控制的共享资源时,该信号量值增加1,如果此时有进程处于休眠状态等待此信号量,则该进程会被唤醒。

使用信号量实现线程通信

Semaphore称为信号量,是引自操作系统的概念。在Java中,Semaphore可以通过permits属性控制线程的并发数。

在使用了Semaphore的编程中,默认情况下所有线程都处于阻塞状态。可以用Semaphore的构造方法设置可执行线程的并发数(如:permits=3),然后通过acquire()方法允许同一时间只能有3个线程同时执行,并且在这3个线程中,如果某个线程执行完毕,就可以调用release()释放一次执行机会,然后从其他等待的线程中随机选择一个来执行。

线程控制案例

package com.geovis.bin.custom.study.wangbin.lock.contion;

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

/**
 * @Author: Wangb
 * @EMail: 1149984363@qq.com
 * @Date: 25/12/2021 上午8:53
 * @Description
 */
public class TestSemaphore {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //同一时间,只允许3个线程并发访问
        Semaphore semaphore = new Semaphore(3);
        //创建20个线程
        for (int i = 0; i < 20; i++) {
             int threadNo = i;
            // execute()方法的参数:重写了run()的Runnable对象
            executorService.execute(() -> {
                try {
                    //同一时间,只能有3个线程获取允许执行
                    semaphore.acquire();
                    System.out.println("得到许可并执行的线程" + threadNo);
                    Thread.sleep((long) Math.random() * 3000);
                    //得到许可的线程执行完毕后,将机会让给其他线程
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            });
        }
        //executorService.shutdown();
    }
}

代码执行结果如下:

同一时间打印出了0 2 1 ,然后逐个打印剩下的线程Id.

以上就是信号量在Java多线程中的通信案例,希望对你有帮助~

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值