ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

信号量Semaphore实现两个线程的交替运行

2022-01-14 11:35:16  阅读:227  来源: 互联网

标签:s0 s1 acquire 信号量 线程 Semaphore release


方法来源:https://www.cnblogs.com/misscai/p/14666782.html

其思路:    使用信号量 Semaphore 有加有减,控制并发。

图出自上方链接。

 

我不理解,两个都是Semapore(1);不可以么?即使不能确定哪个线程先执行,使两个线程交替运行应该是OK的吧。

此时,我对Semaphore的使用还非常不熟悉。

那么验证一下我的猜想。

实现效果:打印1-100的数值,两个线程A B,A线程打印奇数,B线程打印偶数。

public class SemaphoreTest_2 {

    public static void main(String[] args) {
        Semaphore s1 = new Semaphore(1);
        Semaphore s0 = new Semaphore(1);

        new A_th_Semp_2(s0, s1).start();
        new B_th_Semp_2(s0, s1).start();
    }
}

class A_th_Semp_2 extends Thread{

    private Semaphore s0;
    private Semaphore s1;

    public A_th_Semp_2(Semaphore s0, Semaphore s1){
         this.s0 = s0;
         this.s1 = s1;
    }

    @Override
    public void run() {
        for (int i = 1 ; i < 100;){
            try {
                    s1.acquire();
                    System.out.println("线程A:==>"+i);
                    i = i + 2;
                    TimeUnit.SECONDS.sleep(1);
                    s0.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class B_th_Semp_2 extends Thread{

    private Semaphore s0;
    private Semaphore s1;

    public B_th_Semp_2(Semaphore s0, Semaphore s1){
        this.s0 = s0;
        this.s1 = s1;
    }

    @Override
    public void run() {
        for (int i = 2 ; i <= 100;){
            try {
                    s0.acquire();
                    System.out.println("线程B:==>"+i);
                    i = i + 2;
                    TimeUnit.SECONDS.sleep(1);
                    s1.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:显然不太对,orz。以下只是一种运行结果,实际上有可能是B线程先执行。

线程A:==>1
线程B:==>2
线程A:==>3
线程B:==>4
线程B:==>6
线程A:==>5
线程B:==>8
线程A:==>7
线程A:==>9
线程B:==>10
线程A:==>11
线程B:==>12
线程B:==>14 。。。

 

分析原因:

*  * 失败原因在于:
* B线程一个循环结束即s1 release()之后,进入下一个循环时s0.acquire()有可能直接获取到。
*
* 假设A线程先获取s1后打印A完成,进入sleep();此时 B线程获取了s0打印B完成 进入sleep();
* 线程A sleep()完成之后释放s0,进入下一个循环获取s1失败(此时B 线程还是sleep,没有释放s1),在此处阻塞
* 线程B sleep()完成之后释放s1,进入下一个循环获取s0成功(s0由线程A 释放),直接打印B;后进入sleep();
* 线程A 一直在获取s1,此时获取s1成功,打印 A成功后进入sleep();
* 因此出现了连续打印两个B ,连续打印两个A的情况。

是时候研究一下Semaphore的基本使用了。尝试之后,得出了相关结论:

*    信号量Semaphore使用:
* 假设release()N次,就能直接acquire() (N + permits)次!
* permits也可以为负数,没有限制。当(N+permits)> 0 时,acquire();才会成功。
* eg: new Semaphore(-1); 当 连续release 2次之后,就能acquire();成功 1次。
*
* release()并不会 阻塞线程,只有acquire() 会阻塞线程

也就是 Semaphore(0) 的时候,并不是不可以acquire();,只要release();一次那就可以acquire();一次。

acquire(int N); 其实可以有参数获取N个,其效果相当于连续执行了N次acquire();release(int N);同理。

某种程度上Semaphore也是可以循环使用的,只要release() 之后就可以重新 acquire() 。而CountDownLatch是真正意义上的无法循环使用。

Semaphore(0,-1) 类似于单向运行 ,只有在release();执行N次,(N+permits) > 0之后 才能acquire();成功。

 

那么要实现交替打印的功能,只要修改调用代码为:

public class SemaphoreTest_2 {

    public static void main(String[] args) {
        Semaphore s0 = new Semaphore(0);
        Semaphore s1 = new Semaphore(1);

        new A_th_Semp_2(s0, s1).start();
        new B_th_Semp_2(s0, s1).start();

    }
}

 

运行结果:线程A与B交替打印,程序正常关闭。

。。。

线程A:==>87
线程B:==>88
线程A:==>89
线程B:==>90
线程A:==>91
线程B:==>92
线程A:==>93
线程B:==>94
线程A:==>95
线程B:==>96
线程A:==>97
线程B:==>98
线程A:==>99
线程B:==>100

 代码运行流程是:

* 由于s0的permits为0,所以一定是A线程先运行。
* A线程 s1.acquire();成功后执行打印等操作,进入sleep();此时 B线程 s0 依旧acquire();失败
* 当 A线程 休眠完毕,s0.release(); 直接进入下一循环,s1.acquire();时阻塞(由于上个循环acquire();之后并没有release();所以再次 .acquire();时阻塞 )
* 此时 B线程 s0.acquire();成功 (A线程 上个循环释放了s0),执行打印等操作之后,进入sleep;此时 A线程s1.acquire(); 依旧失败,理由同上;
* 当 B线程 休眠完毕,s1.release();直接进入下一循环,s0.acquire();时阻塞。(由于A 线程上个循环的release();被B 线程的上个循环使用了,需等待下一个relase;)
* 此时 A线程 s1.acquire();时成功,继续执行第二个循环的逻辑
* 以此类推

其实整个思路就是利用了Semaphore(0);的单向运行,Semaphore(-1,-2)其实都拥有这个特性,也能实现相应的功能,只是可以但没必要。

具体做法就是修改一下两处代码:

main(xxx);中初始化时s0改为-1;A线程中 s0.release();改为s0.release(2);

Semaphore s0 = new Semaphore(-1);
s0.release(2);

运行效果自行验证。

标签:s0,s1,acquire,信号量,线程,Semaphore,release
来源: https://www.cnblogs.com/CccccNun/p/15798454.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有