多线程并发/多线程协作 以及volatile关键字的使用-问题拆解

  1. 交替打印 FooBar
    给你一个类:
class FooBar {
  public void foo() {
    for (int i = 0; i < n; i++) {
      print("foo");
    }
  }

  public void bar() {
    for (int i = 0; i < n; i++) {
      print("bar");
    }
  }
}

两个不同的线程将会共用一个 FooBar 实例:

线程 A 将会调用 foo() 方法,而
线程 B 将会调用 bar() 方法
请设计修改程序,以确保 “foobar” 被输出 n 次。

示例 1:

输入:n = 1
输出:"foobar"
解释:这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。

问题分析:
对于上面的问题,我们可以知道,是解决两个线程协作的问题;

分析如下:我们可以知道当前只有两个线程,我记为线程A和线程B,对于这两个线程,分别去执行foo()和bar()方法;我们还能知道,foo方法只有一个线程在调用,bar方法也是只有一个线程在调用,因此foo/bar方法并不存在并发的问题;,所以该问题只是简单的归类为协作问题(用一个状态即可解决,而没必要要用锁的信号量机制,太重了!);

以下代码能成功实现协作的一大原因是volatile修饰了permitFoo;

//自旋 + 让出CPU
class FooBar {
    private int n;

    public FooBar(int n) {
        this.n = n;
    }

    volatile boolean permitFoo = true;

    public void foo(Runnable printFoo) throws InterruptedException {     
        for (int i = 0; i < n; ) {
            if(permitFoo) {
        	    printFoo.run(); //这个操作需要在permitFoo=false之前;
            	i++;
            	permitFoo = false;
            }else{
                Thread.yield();//主动让出cpu
            }
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {       
        for (int i = 0; i < n; ) {
            if(!permitFoo) {
        	printBar.run();
        	i++;
        	permitFoo = true; 
            }else{
                Thread.yield();
            }
        }
    }
}


那如果说问题升级为一个foo方法存在多并发的场景呢?这又如何解决呢?那就需要同步机制了,这个时候可以引出锁,直接用一个lock锁住对应的代码块就行,或者说直接加一个synchronized关键字加在方法或者同样代码块的方式即可;类似如下

class testJustTwoThread{
    ReentrantLock lock = new ReentrantLock();
    volatile boolean flag = false; //乐观锁机制可见性
    public void pop(){
        for (int i = 0; i < 100;) {
            lock.lock(); //防止多线程并发访问该代码块
            try {
                //借助volatile关键字修饰的变量进行线程协作。。
                if(flag){
                    System.out.println("A");
                    flag = false; 
                    i++;
                }else{
                    //没有执行i++,其实算是一种自旋操作
                    //主动让出cpu的方式
                    Thread.yield();
                }
            }finally {
                lock.unlock();
            }

        }
    }
    public void push(){
        for (int i = 0; i < 100;) {
            lock.lock();
            try {
                if(!flag){
                    System.out.println("B");
                    flag = true;  
                    i++;
                }else{
                    //没有执行i++,其实算是一种自旋操作
                    //主动让出cpu的方式
                    Thread.yield();
                }
            }finally {
                lock.unlock();
            }

        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

践行~渐远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值