0
点赞
收藏
分享

微信扫一扫

苹果-桔子线程【操作系统】

i奇异 2022-05-06 阅读 36

苹果-桔子线程

题目

  1. 桌上有一空盘,允许存放一个水果。
  • 爸爸可向盘中存放苹果,也可向盘中存放桔子,
  • 儿子专等吃盘中的桔子,
  • 女儿专等吃盘中的苹果。
  • 规定当盘空时一次只能放一只水果供吃者取用,
  • 请用P、V原语实现爸爸、儿子、 女儿三个并发进程的同步。
  1. 桌上有一空盘,最多允许存放两个水果。
  • 爸爸可向盘中存放苹果,
  • 妈妈可向盘中存放桔子,
  • 儿子专等吃盘中的桔子,
  • 女儿专等吃盘中的苹果。
  • 规定当盘空时一次只能放一只水果供吃者取用,
  • 请用P、V原语实现爸爸、儿子、 女儿三个并发进程的同步。
  1. 桌上有一空盘,只允许存放一个水果。
  • 爸爸可向盘中存放苹果,
  • 妈妈可向盘中存放桔子,
  • 儿子专等吃盘中的桔子,
  • 女儿专等吃盘中的苹果。
  • 规定当盘空时一次只能放一只水果供吃者取用,
  • 请用P、V原语实现爸爸、儿子、 女儿三个并发进程的同步。

实现

用随机数来实现父亲是放桔子还是苹果
package os.apple_orange;

import java.util.concurrent.Semaphore;
/**
 * Eg.1、桌上有一空盘,允许存放一个水果。
 * 爸爸可向盘中存放苹果,也可向盘中存放桔子,
 * 儿子专等吃盘中的桔子,
 * 女儿专等吃盘中的苹果。
 * 规定当盘空时一次只能放一只水果供吃者取用,
 * 请用P、V原语实现爸爸、儿子、  女儿三个并发进程的同步。
 *
 * 信号量Semaphore 通过使用计数器counter来控制对共享资源的访问。
 * 如果计数器大于零,则允许访问。如果为零,则拒绝访问。
 * 计数器对共享资源的访问许可进行计数。因此,要访问资源,线程必须要从信号量得到许可。
 */
public class ProcessTest1 {

//    permits 初始许可数,也就是最大访问线程数
//    fair 当设置为false时,创建的信号量为非公平锁;当设置为true时,信号量是公平锁
    static Semaphore empty = new Semaphore(1,false);//资源区是否为空
    static Semaphore orange = new Semaphore(0,false);//资源区桔子信号
    static Semaphore apple = new Semaphore(0,false);//资源区苹果信号

    public static void main(String[] args) {
        //父亲的进程
        Thread father = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        empty.acquire();//申请操作权限相当于wait(S)
                        int random = Math.random() >= 0.5 ? 1 : 0;
                        if (random == 1) {
                            System.out.println("父亲放入了一个桔子");
                            Thread.sleep(1000);//休眠表示放入的过程
                            orange.release();//唤醒儿子的访问,相当于signal(orange)
                        } else {
                            System.out.println("父亲放入了一个苹果");
                            Thread.sleep(1000);
                            apple.release();//唤醒女儿的访问,相当于signal(apple)
                        }
                    } catch (InterruptedException e) {
                        System.out.println("父亲获取资源失败!");
                        e.printStackTrace();
                    }
                }
            }
        });
        //女儿的进程
        Thread daughter = new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        apple.acquire();//女儿获取apple的资源,相当于wait(apple)
                        System.out.println("女儿取走了一个苹果!");
                        Thread.sleep(1000);//取走的过程
                        empty.release();//释放资源,相当于signal(S)
                    } catch (InterruptedException e) {
                        System.out.println("女儿获取资源失败!");
                        e.printStackTrace();

                    }
                }
            }
        });
        //儿子的进程
        Thread son = new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        orange.acquire();//儿子获取orange资源,相当于wait(apple)
                        System.out.println("儿子取走了一个桔子!");
                        Thread.sleep(1000);//取的过程
                        empty.release();//释放资源,相当于signal(S)
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        System.out.println("儿子获取资源失败!");
                    }
                }
            }
        });
        father.setName("父亲");
        daughter.setName("女儿");
        son.setName("儿子");
        father.start();
        daughter.start();
        son.start();
    }

}



运行结果

父亲放入了一个苹果
女儿取走了一个苹果!
父亲放入了一个桔子
儿子取走了一个桔子!
父亲放入了一个桔子
儿子取走了一个桔子!
父亲放入了一个苹果
女儿取走了一个苹果!

和1的区别在于

  • 增加母亲进程
 //母亲的进程
Thread mother;
  • 并且修改了盘子允许放水果的数量
 //修改了盘子允许放水果的数量
 static Semaphore empty = new Semaphore(1,false);//资源区是否为空

代码如下

package os.apple_orange;

import java.util.concurrent.Semaphore;

/**
 * 桌上有一空盘,最多允许存放两个水果。
 * 爸爸可向盘中存放苹果,
 * 妈妈可向盘中存放桔子,
 * 儿子专等吃盘中的桔子,
 * 女儿专等吃盘中的苹果。
 * 规定当盘空时一次只能放一只水果供吃者取用,
 * 请用P、V原语实现爸爸、儿子、  女儿三个并发进程的同步。
 */


public class ProcessTest2 {

//    permits 初始许可数,也就是最大访问线程数
//    fair 当设置为false时,创建的信号量为非公平锁;当设置为true时,信号量是公平锁
    static Semaphore empty = new Semaphore(2,false);//资源区是否为空
    static Semaphore orange = new Semaphore(0,false);//资源区桔子信号
    static Semaphore apple = new Semaphore(0,false);//资源区苹果信号

    public static void main(String[] args) {
        //父亲的进程
        Thread father = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        empty.acquire();//申请操作权限相当于wait(S)
                        System.out.println("父亲放入了一个苹果");
                        Thread.sleep(1000);
                        apple.release();//唤醒女儿的访问,相当于signal(apple)
                    } catch (InterruptedException e) {
                        System.out.println("父亲获取资源失败!");
                        e.printStackTrace();
                    }
                }
            }
        });
        //母亲的进程
        Thread mother = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        empty.acquire();//申请操作权限相当于wait(S)
                        System.out.println("母亲放入了一个桔子");
                        Thread.sleep(1000);//休眠表示放入的过程
                        orange.release();//唤醒儿子的访问,相当于signal(orange)
                    } catch (InterruptedException e) {
                        System.out.println("母亲获取资源失败!");
                        e.printStackTrace();
                    }
                }
            }
        });
        //女儿的进程
        Thread daughter = new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        apple.acquire();//女儿获取apple的资源,相当于wait(apple)
                        System.out.println("女儿取走了一个苹果!");
                        Thread.sleep(1000);//取走的过程
                        empty.release();//释放资源,相当于signal(S)
                    } catch (InterruptedException e) {
                        System.out.println("女儿获取资源失败!");
                        e.printStackTrace();

                    }
                }
            }
        });
        //儿子的进程
        Thread son = new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        orange.acquire();//儿子获取orange资源,相当于wait(apple)
                        System.out.println("儿子取走了一个桔子!");
                        Thread.sleep(1000);//取的过程
                        empty.release();//释放资源,相当于signal(S)
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        System.out.println("儿子获取资源失败!");
                    }
                }
            }
        });
        father.setName("父亲");
        mother.setName("母亲");
        daughter.setName("女儿");
        son.setName("儿子");
        father.start();
        mother.start();
        daughter.start();
        son.start();
    }

}




运行结果

父亲放入了一个苹果
母亲放入了一个桔子
女儿取走了一个苹果!
儿子取走了一个桔子!
父亲放入了一个苹果
母亲放入了一个桔子
儿子取走了一个桔子!
女儿取走了一个苹果!
母亲放入了一个桔子
父亲放入了一个苹果
儿子取走了一个桔子!
女儿取走了一个苹果!
母亲放入了一个桔子
父亲放入了一个苹果
女儿取走了一个苹果!
儿子取走了一个桔子!
  • 和2的区别仅仅在于
 //修改了盘子允许放水果的数量
 static Semaphore empty = new Semaphore(1,false);//资源区是否为空
package os.apple_orange;

import java.util.concurrent.Semaphore;

/**
 * 桌上有一空盘,只允许存放一个水果。
 * 爸爸可向盘中存放苹果,
 * 妈妈可向盘中存放桔子,
 * 儿子专等吃盘中的桔子,
 * 女儿专等吃盘中的苹果。
 * 规定当盘空时一次只能放一只水果供吃者取用,
 * 请用P、V原语实现爸爸、儿子、  女儿三个并发进程的同步。
 */


public class ProcessTest3 {

//    permits 初始许可数,也就是最大访问线程数
//    fair 当设置为false时,创建的信号量为非公平锁;当设置为true时,信号量是公平锁
    static Semaphore empty = new Semaphore(1,false);//资源区是否为空
    static Semaphore orange = new Semaphore(0,false);//资源区桔子信号
    static Semaphore apple = new Semaphore(0,false);//资源区苹果信号

    public static void main(String[] args) {
        //父亲的进程
        Thread father = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        empty.acquire();//申请操作权限相当于wait(S)
                        System.out.println("父亲放入了一个苹果");
                        Thread.sleep(1000);
                        apple.release();//唤醒女儿的访问,相当于signal(apple)
                    } catch (InterruptedException e) {
                        System.out.println("父亲获取资源失败!");
                        e.printStackTrace();
                    }
                }
            }
        });
        //母亲的进程
        Thread mother = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        empty.acquire();//申请操作权限相当于wait(S)
                        System.out.println("母亲放入了一个桔子");
                        Thread.sleep(1000);//休眠表示放入的过程
                        orange.release();//唤醒儿子的访问,相当于signal(orange)
                    } catch (InterruptedException e) {
                        System.out.println("母亲获取资源失败!");
                        e.printStackTrace();
                    }
                }
            }
        });
        //女儿的进程
        Thread daughter = new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        apple.acquire();//女儿获取apple的资源,相当于wait(apple)
                        System.out.println("女儿取走了一个苹果!");
                        Thread.sleep(1000);//取走的过程
                        empty.release();//释放资源,相当于signal(S)
                    } catch (InterruptedException e) {
                        System.out.println("女儿获取资源失败!");
                        e.printStackTrace();

                    }
                }
            }
        });
        //儿子的进程
        Thread son = new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        orange.acquire();//儿子获取orange资源,相当于wait(apple)
                        System.out.println("儿子取走了一个桔子!");
                        Thread.sleep(1000);//取的过程
                        empty.release();//释放资源,相当于signal(S)
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        System.out.println("儿子获取资源失败!");
                    }
                }
            }
        });
        father.setName("父亲");
        mother.setName("母亲");
        daughter.setName("女儿");
        son.setName("儿子");
        father.start();
        mother.start();
        daughter.start();
        son.start();
    }

}


运行结果

父亲放入了一个苹果
女儿取走了一个苹果!
母亲放入了一个桔子
儿子取走了一个桔子!
父亲放入了一个苹果
女儿取走了一个苹果!
母亲放入了一个桔子
儿子取走了一个桔子!

资料

Java Semaphore详解
1、介绍
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,通过协调各个线程以保证合理地使用公共资源。

Semaphore通过使用计数器来控制对共享资源的访问。 如果计数器大于0,则允许访问。 如果为0,则拒绝访问。 计数器所计数的是允许访问共享资源的许可。 因此,要访问资源,必须从信号量中授予线程许可。

2、主要方法

void acquire() :从信号量获取一个许可,如果无可用许可前将一直阻塞等待,

void release():释放一个许可。

3、Semaphore构造函数

 public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

permits 初始许可数,也就是最大访问线程数
fair 当设置为false时,创建的信号量为非公平锁;当设置为true时,信号量是公平锁
关于java非公平锁和公平锁可以看这篇文章:一文搞懂java中的锁
4、公平锁 和 非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。公平锁的优点是等待锁的线程不会饿死。缺点是整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

非公平锁是多个线程加锁时直接尝试获取锁,获取不到才会到等待队列的队尾等待。但如果此时锁刚好可用,那么这个线程可以无需阻塞直接获取到锁,所以非公平锁有可能出现后申请锁的线程先获取锁的场景。非公平锁的优点是可以减少唤起线程的开销,整体的吞吐效率高,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。缺点是处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

举报

相关推荐

0 条评论