java多线程同步例题-三种常用解法

Java多线程题目 不同解决办法

题目 两个线程轮换打印foo 和bar

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 次

思考:本质上两个函数对应两个线程 线程实际就是函数的执行过程,两个不同线程对应两个函数
一个函数打印foo
一个函数打印bar
中间怎么同步,需要共享变量,变量无非三种 静态 实例变量 局部变量
函数无非是对变量操作
静态变量 所有对象所有方法都共享
范围:
不同对象的同一方法,
不同对象的不同方法
同一对象的不同方法
实例变量 单一对象的所有方法都共享
范围:
同一对象的不同方法
此题用实例变量就可以解决

方法1:自旋锁+出让CPU

自旋锁的目的是为了解决同步问题而不是互斥问题
单核cpu需要 线程让出 yield() 目的是不让出 会一直空转 有可能 超时 。不让出 就是等时间片用完 再线程调度 也需要线程切换 结果:线程切换会进入内核态
多核cpu不需要 线程让出 不存在线程切换 大大提高效率 线程空转 也不需要切换线程 全部在用户态,没有进入内核态
操作系统指挥线程切换, 操作系统在内核态指挥线程切换

class FooBar5 {
    private int n;

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

    volatile boolean permitFoo = true;

    public void foo() throws InterruptedException {     
        for (int i = 0; i < n; ) {
            if(permitFoo) {
        	    printFoo();
            	i++;
            	permitFoo = false;
            }else{
                Thread.yield();
            }
        }
    }

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

方法2 synchronized + 标志位 + 唤醒

通常先互斥 再通过循环同步
线程阻塞时的特点:
该线程放弃CPU的使用权,暂停运行,只有当阻塞的原因消除后才回到就绪状态进行运行

synchronized的作用:互斥
线程a获得锁执行了一段同步代码,线程b竞争同一把锁由于无法获得相关的同步锁,只能进入阻塞状态,等获取了同步锁,才能恢复运行

wait作用:同步
wait必须要在synchronized中使用
wait的前提是有锁
1.先释放锁
2.进行阻塞等待
3.收到通知之后,重新尝试获取锁,并且在获取锁后,继续往下执行.

class FooBar3 {
    private int n;
    // 标志位,控制执行顺序,true执行printFoo,false执行printBar
    private volatile boolean type = true;
    private final Object foo=  new Object(); // 锁标志

    public FooBar3(int n) {
        this.n = n;
    }
    public void foo() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            synchronized (foo) {
                while(!type){
                    foo.wait();
                }
                printFoo();
                type = false;
                foo.notifyAll();
            }
        }
    }

    public void bar() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            synchronized (foo) {
                while(type){
                    foo.wait();
                }
                printBar();
                type = true;
                foo.notifyAll();
            }
        }
    }
}

给出方法2的多线程具体实现-内部类

public class FooBar3Main {
    public static void main(String[] args) {
        // 假设n的值为10
        int n = 10;
        FooBar3 fooBar3 = new FooBar3(n);

        // 创建两个线程分别调用foo和bar方法lamda表达式简化
        Thread threadFoo = new Thread(() -> {
            try {
                fooBar3.foo();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread threadBar = new Thread(() -> {
            try {
                fooBar3.bar();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 启动线程
        threadFoo.start();
        threadBar.start();

    }

   
}
外部类 写两个
 两个 thread类 都用 foobar类做对象  run方法执行不同的 函数 foo或bar函数   

方法3 信号量 适合控制顺序

class FooBar2 {
    private int n;
    private Semaphore foo = new Semaphore(1);
    private Semaphore bar = new Semaphore(0);
    public FooBar2(int n) {
        this.n = n;
    }

    public void foo() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            foo.acquire();
        	printFoo();
            bar.release();
        }
    }
    public void bar(Runnable printBar) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            bar.acquire();
        	printBar();
            foo.release();
        }
    }
}
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值