Semaphore介绍

1、概述

     信号量,多线程多任务同步,一个线程完成某个动作就通过信号量告诉别的线程,别的线程在进行某些动作。

2、上锁

      信号量大于0,其他线程就等待,成功后信号量的值-1。值不大于0,则线程阻塞,直到信号量的值+1。

      常用的两个主要方法:

       acquire()

       release()

3、实际中的一个例子:abc三个线程交替打印147、258、369

package com.test.abc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Semaphore;

@Slf4j
public class ThreadTestSemaphoreA {

    public static void main(String[] args) {

        Semaphore a = new Semaphore(1);
        Semaphore b = new Semaphore(0);
        Semaphore c = new Semaphore(0);

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 1; i < 10; i = i + 3) {
                    try {
                        a.acquire();
                        System.out.println("a线程:" + i);

                    } catch (Exception e) {
                        log.error("a线程异常", e);
                    } finally {
                        b.release();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 2; i < 10; i = i + 3) {
                    try {
                        b.acquire();
                        System.out.println("b线程:" + i);

                    } catch (Exception e) {
                        log.error("b线程异常", e);
                    } finally {
                        c.release();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 3; i < 10; i = i + 3) {
                    try {
                        c.acquire();
                        System.out.println("c线程:" + i);

                    } catch (Exception e) {
                        log.error("c线程异常", e);
                    } finally {
                        a.release();
                    }
                }
            }
        }).start();
    }
}

 打印结果如下:

a线程:1
b线程:2
c线程:3
a线程:4
b线程:5
c线程:6
a线程:7
b线程:8
c线程:9

4、思考:

      信号量固然能实现三个线程的交替打印,从实现上讲,代码段并无问题。然而信号量是用来做这个的么?

      我们来改变下信号量的值,进行测试:

package com.test.abc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Semaphore;

@Slf4j
public class ThreadTestSemaphoreA {

    public static void main(String[] args) {

        Semaphore a = new Semaphore(2);
        Semaphore b = new Semaphore(0);
        Semaphore c = new Semaphore(0);

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 1; i < 10; i = i + 3) {
                    try {
                        a.acquire();
                        System.out.println("a线程:" + i);

                    } catch (Exception e) {
                        log.error("a线程异常", e);
                    } finally {
                        b.release();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 2; i < 10; i = i + 3) {
                    try {
                        b.acquire();
                        System.out.println("b线程:" + i);

                    } catch (Exception e) {
                        log.error("b线程异常", e);
                    } finally {
                        c.release();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 3; i < 10; i = i + 3) {
                    try {
                        c.acquire();
                        System.out.println("c线程:" + i);

                    } catch (Exception e) {
                        log.error("c线程异常", e);
                    } finally {
                        a.release();
                    }
                }
            }
        }).start();
    }
}

   执行结果:      

a线程:1
a线程:4
b线程:2
b线程:5
c线程:3
c线程:6
a线程:7
b线程:8
c线程:9

   上文可以看出:这是实现了三个线程,分别打印147 258 369,且每个线程打印两次的实例。

   如果这样还不能看出问题,那么我们换种方式:

package com.test.abc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Semaphore;

@Slf4j
public class ThreadTestSemaphoreA {

    public static void main(String[] args) {

        Semaphore a = new Semaphore(3);

        for (int i = 1; i < 10; i++) {
            new Thread(new MyThread(a, "第" + i + "个")).start();
        }
    }

    static class MyThread implements Runnable {

        private Semaphore semaphore;

        private String name;

        MyThread(Semaphore semaphore, String name) {
            this.semaphore = semaphore;
            this.name = name;
        }

        @Override
        public void run() {
            int permits = semaphore.availablePermits();
            if (permits > 0) {
                System.out.println(name + "线程。" + "大于0,不可用");
            } else {
                System.out.println(name + "线程。" + "不大于0,等待");
            }
            try {
                semaphore.acquire();
                System.out.println(name + "线程。" + "占用");
                Thread.sleep(100);
                System.out.println(name + "线程。" + "使用完毕");
            } catch (Exception e) {
                log.error("a线程异常", e);
            } finally {
                semaphore.release();
            }
        }
    }
}

执行结果:

第1个线程。大于0,不可用
第1个线程。占用
第2个线程。大于0,不可用
第2个线程。占用
第3个线程。大于0,不可用
第3个线程。占用
第4个线程。不大于0,等待
第7个线程。不大于0,等待
第6个线程。不大于0,等待
第5个线程。不大于0,等待
第8个线程。不大于0,等待
第9个线程。不大于0,等待
第1个线程。使用完毕
第2个线程。使用完毕
第3个线程。使用完毕
第7个线程。占用
第4个线程。占用
第6个线程。占用
第7个线程。使用完毕
第5个线程。占用
第4个线程。使用完毕
第8个线程。占用
第6个线程。使用完毕
第9个线程。占用
第5个线程。使用完毕
第8个线程。使用完毕
第9个线程。使用完毕

这次执行结果,估计都能看出来了,这像不像是上厕所排队的例子?

最后总结:

信号量本身并不是专门为互斥锁设计的,或者说信号量为0 1时为二进制信号量。但更多的是计数信号量,真正的多线程协调。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值