问:操作系统三大经典同步问题,你如何复现?

作为操作系统中的最基本模型,在面试中被要求书写的可能性还是很大的,如果只是伪码,这还是一个简单的问题,但是要你具体实现呢?你会使用什么样的方式来实现这件事情呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7BBbHDBF-1590999089217)(https://upload-images.jianshu.io/upload_images/23124486-cb7d2fdc9f8803fc?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

生产者、消费者问题

什么是生产者、消费者问题?

image

意思很简单,就是生产者给生产链生产,而消费者从生产链中拿出。那关键点已经出来了,问题就在于怎么处理这一条生产链(正规叫法应该叫缓冲区)?

伪码实现

 1// 变量
 2list = buffer[n] // 生产链,容量为n
 3,mutex = 1 // 互斥使用生产链
 4,empty = n // 消费后剩余
 5,full = 0 // 生产后容量
 6
 7// 两个运作对象:及对应动作
 8producer:product // 生产者生产
 9consumer:consume // 消费者消费
10
11// 两个动作
12product{
13    wait(empty) // 生产链不满
14    wait(mutex)
15    // 生产
16    signal(mutex)
17    signal(full) // 给生产链加一个产品
18}
19consumer{
20    wait(full) // 生产链不为空
21    wait(mutex)
22    // 消费
23    signal(mutex)
24    signal(empty) // 生产链中的产品又被消耗
25}

具体代码实现

 1class ProducerAndConsumer {
 2    private final int MAX_LEN = 10;
 3    private Queue<Integer> queue = new LinkedList<Integer>();
 4    Semaphore producer = new Semaphore(0);
 5    Semaphore consumer = new Semaphore(MAX_LEN);
 6    Semaphore lock = new Semaphore(1);
 7
 8    // 生产者
 9    class Producer extends Thread {
10        @Override
11        public void run() {
12            while (true) {
13                try {
14                    consumer.acquire(); // 可消费的数量未满
15                    lock.acquire(); // 临界区
16                    queue.add(1);
17                    System.out.println("consumer size:" + queue.size());
18                    Thread.sleep(200);
19                } catch (InterruptedException e) {
20                    e.printStackTrace();
21                } finally {
22                    lock.release();
23                    producer.release();
24                }
25            }
26        }
27    }
28    // 消费者
29    class Consumer extends Thread {
30        @Override
31        public void run() {
32            while (true) {
33                try {
34                    producer.acquire(); // 还剩余产品
35                    lock.acquire(); // 临界区
36                    queue.remove();
37                    System.out.println("consumer size:" + queue.size());
38                    Thread.sleep(200);
39                } catch (InterruptedException e) {
40                    e.printStackTrace();
41                } finally {
42                    lock.release();
43                    consumer.release();
44                }
45            }
46        }
47    }
48
49
50    public static void main(String[] args) {
51        ProducerAndConsumer producerAndConsumer = new ProducerAndConsumer();
52        Producer producer = producerAndConsumer.new Producer();
53        Consumer consumer = producerAndConsumer.new Consumer();
54        producer.start();
55        consumer.start();
56    }
57}

哲学家就餐问题

image

五把叉子,五个人,如果每个人都拿起了叉子,那么整桌的人必然就没饭吃了,哲学家问题思考的就是这样的一个问题。

伪码实现

 1// 变量
 2forks = {1, 1, 1, 1, 1} // 暂定为5人
 3
 4// 一个被运作对象:以及动作
 5fork:handle、release
 6Philosopher:thinking、eating
 7
 8// 动作,eating和thinking是两个Thread.sleep完成
 9handle {
10    // 左右手只要有一只被拿起,就需要等待
11    // 如果不等带,就可能每个人只拿一只
12    while(forks[postion] == 0 || forks[(position + 1) % 5] == 0){
13        wait() // 等待
14    }
15    forks[postion] == 0;
16    forks[(position + 1) % 5] == 0;
17}
18
19release {
20    // 吃完以后把东西放下
21    forks[postion] == 1;
22    forks[(position + 1) % 5] == 1;
23}

具体代码实现

 1public class PhilosopherEat {
 2    class Philosopher extends Thread {
 3        private String name;
 4        private Fork fork;
 5
 6        public Philosopher(String name, Fork fork) {
 7            super(name);
 8            this.name = name;
 9            this.fork = fork;
10        }
11
12        @Override
13        public void run() {
14            // 哲学家需要完成要的一系列动作
15            while (true) {
16                thinking();
17                fork.takeFork();
18                eating();
19                fork.putFork();
20            }
21        }
22
23        public void eating() {
24            System.out.println("I am Eating:" + name);
25            try {
26                //模拟吃饭
27                sleep(1000);
28            } catch (InterruptedException e) {
29                // TODO Auto-generated catch block
30                e.printStackTrace();
31            }
32        }
33
34        public void thinking() {
35            System.out.println("I am Thinking:" + name);
36            try {
37                //模拟思考
38                sleep(1000);
39            } catch (InterruptedException e) {
40                e.printStackTrace();
41            }
42        }
43    }
44
45    class Fork{
46        // 5根筷子
47        private boolean[] used={false,false,false,false,false,false};
48
49        public synchronized void takeFork(){
50            String name = Thread.currentThread().getName();
51            int i = Integer.parseInt(name);
52            // 如果左右手有一只正被使用就等待
53            while(used[i]||used[(i+1)%5]){
54                try {
55                    wait();
56                } catch (InterruptedException e) {
57                    e.printStackTrace();
58                }
59            }
60            used[i ]= true;
61            used[(i+1)%5]=true;
62        }
63
64        // 同时释放左右手的筷子
65        public synchronized void putFork(){
66            String name = Thread.currentThread().getName();
67            int i = Integer.parseInt(name);
68            used[i ]= false;
69            used[(i+1)%5]=false;
70            notifyAll();
71        }
72    }
73
74    public static void main(String[] args) {
75        PhilosopherEat philosopher = new PhilosopherEat();
76        Fork fork = philosopher.new Fork();
77        philosopher.new Philosopher("0",fork).start();
78        philosopher.new Philosopher("1",fork).start();
79        philosopher.new Philosopher("2",fork).start();
80        philosopher.new Philosopher("3",fork).start();
81        philosopher.new Philosopher("4",fork).start();
82    }
83}

读者写者问题

image

读者写者问题针对的就是我们的数据问题,你在 wps 打开一个文件,又在 word 打开一个文件势必会看到一个只读的模式会弹出,这就是读者写着问题的具体表现了。

伪码实现

 1// 变量
 2readCount // 当前读书的人数
 3,readLock // 读者锁
 4,writeLock // 写者锁
 5
 6// 两个对象:及其动作
 7Reader:read
 8Writer:write
 9
10// 动作
11read{
12    p(readLock)
13        if(readCount == 0) p(writeLock) // 第一个读者进入后,就不可修改
14        readCount++
15    v(readLock)
16
17    // 。。。读书
18
19    p(readLock)
20        readCount--
21        if(readCount == 0) v(writeLock) // 最后一个读者走后,可以开始修改
22    v(readLock)
23}
24
25write{
26    p(writeLock)
27    // 。。。修改
28    v(writeLock)
29}

具体代码实现

 1import java.util.concurrent.Semaphore;
 2
 3public class ReaderAndWriter {
 4    public static void main(String[] args) {
 5        // 实现写者与写者间、读者与写者间互斥
 6        Semaphore wmutex = new Semaphore(1);
 7        // 用于改变 readCount 变量时实现互斥
 8        Semaphore rmutex = new Semaphore(1);
 9        for (int i = 0; i < 3; ++i) {
10            new Reader(rmutex, wmutex).start();
11            new Writer(wmutex).start();
12        }
13    }
14}
15
16class Reader extends Thread {
17    private static int total = 0;
18    private int id;
19    private Semaphore rmutex, wmutex;
20    private static int readCount = 0;
21
22    public Reader(Semaphore rmutex, Semaphore wmutex) {
23        id = ++total;
24        this.rmutex = rmutex;
25        this.wmutex = wmutex;
26    }
27
28    @Override
29    public void run() {
30        while (true) {
31            try {
32                rmutex.acquire();
33                // 只有第一个读者进程需要执行 wmutex.p()
34                if (readCount == 0) wmutex.acquire();
35                readCount++;
36                System.out.println(id + " 号读者在读");
37            } catch (Exception e) {
38            } finally {
39                rmutex.release();
40            }
41            // 模拟读书
42            try {
43                Thread.sleep(30);
44            } catch (InterruptedException e) {
45                e.printStackTrace();
46            }
47            // 读书人出去了
48            try {
49                rmutex.acquire();
50                readCount--;
51                System.out.println(id + " 号读者结束阅读:当前还剩 " + readCount + " 位读者在读");
52                if (readCount == 0) wmutex.release();
53            } catch (Exception e) {
54            } finally {
55                rmutex.release();
56            }
57        }
58    }
59}
60
61class Writer extends Thread {
62    private static int total = 0;
63    private int id;
64    private Semaphore wmutex;
65
66    public Writer(Semaphore wmutex) {
67        id = ++total;
68        this.wmutex = wmutex;
69    }
70
71    @Override
72    public void run() {
73        while (true) {
74            try {
75                wmutex.acquire();
76                // 执行写操作
77                System.out.println(id + " 号写者正在写");
78                wmutex.release();
79            } catch (InterruptedException e) {
80                e.printStackTrace();
81            }
82            // 线程休眠一段时间,总不会一直改的
83            try {
84                Thread.sleep(300);
85            } catch (InterruptedException e) {
86                e.printStackTrace();
87            }
88        }
89    }
90}

原文链接 https://juejin.im/post/5e59fe90f265da574657d9e8

服务推荐

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值