操作系统&java多线程技术几种信号量机制算法
Posted 九死九歌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了操作系统&java多线程技术几种信号量机制算法相关的知识,希望对你有一定的参考价值。
生产者消费者问题:
太经典了,就不多赘述了。
import java.util.concurrent.Semaphore;
public class ProducerAndConsumer {
static int count = 0;
private static final Semaphore full = new Semaphore(0);
private static final Semaphore empty = new Semaphore(20);
private static final Semaphore mutex = new Semaphore(1);
public static void main(String[] args) {
new Thread(()->{
while (true) {
try {
Thread.sleep(100);
empty.acquire();
mutex.acquire();
System.out.println("生产者生产了一个临界区资源,目前还有" + ++count + "个临界区资源。");
mutex.release();
full.release();
} catch (InterruptedException e) {
System.err.println("出现了某种状况导致线程不安全");
}
}
}).start();
new Thread(()->{
while (true) {
try {
Thread.sleep(100);
full.acquire();
mutex.acquire();
System.out.println("消费者消费了一个临界区资源,目前还有" + --count + "个临界区资源。");
mutex.release();
empty.release();
} catch (InterruptedException e) {
System.err.println("出现了某种状况导致线程不安全");
}
}
}).start();
}
}
多生产者消费者问题:
一家四口人,爸爸妈妈女儿儿子在吃饭,桌上有一个盘子,每次只能由家长向其中放一个水果,爸爸专门放苹果,妈妈专门放橘子,儿子等着吃橘子,女儿等着吃苹果。
import java.util.concurrent.Semaphore;
/**
* <b>同步关系:</b>
* <li>父亲放了苹果之后女儿才能吃苹果</li>
* <li>母亲放了橘子之后儿子才能吃橘子</li>
* <li>只有盘子为空时,父母才能放水果</li>
* <b>互斥关系:</b>
* <li>同时只能有一个人从盘子拿东西或往盘子放东西</li>
*/
public class MultiProducerAndConsume {
private static final Semaphore orange = new Semaphore(0);
private static final Semaphore apple = new Semaphore(0);
private static final Semaphore plate = new Semaphore(1);
public static void main(String[] args) {
new Thread(()->{
while (true) {
try {
Thread.sleep(100);
plate.acquire();
System.out.println(Thread.currentThread().getName() + "把苹果放到了盘子中给女儿吃。");
apple.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "父亲").start();
new Thread(()->{
while (true) {
try {
Thread.sleep(100);
plate.acquire();
System.out.println(Thread.currentThread().getName() + "把橘子放到了盘子中给儿子吃。");
orange.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "母亲").start();
new Thread(()->{
while (true) {
try {
Thread.sleep(100);
apple.acquire();
System.out.println(Thread.currentThread().getName() + "吃掉了爸爸给的苹果。");
plate.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "女儿").start();
new Thread(()->{
while (true) {
try {
Thread.sleep(100);
orange.acquire();
System.out.println(Thread.currentThread().getName() + "吃掉了妈妈给的橘子。");
plate.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "儿子").start();
}
}
由于缓冲区大小为1,所以不需要mutex信号量也能保证互斥,不需要像上面那个一样设置mutex,但是如果是盘子里一次能放2个水果就必须得有一个mutex了,否则父亲对盘子p操作完后,盘子剩一个空,母亲也对盘子p操作,盘子没空了,然后父母同时放水果,他们有可能放的是盘子的统一个位置,也就是造成数据覆盖。
吸烟者问题:
有三个手上没有烟的吸烟者,他们分别有:烟草、纸和胶水。他们想要抽烟就必须得得到另外两种材料。另外还有一个供应者,会免费的轮流供应三个吸烟者缺少的两种材料放在桌子(临界缓冲区)上供吸烟者自己制作香烟并吸烟。
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
/**
* <b>同步关系:</b>
* <li>桌上有组合一(纸 + 胶水)&rarr 第一个吸烟者吸烟</li>
* <li>桌上有组合二(烟草 + 胶水) &rarr 第二个吸烟者吸烟</li>
* <li>桌上有组合三(烟草 + 纸) &rarr 第三个吸烟者吸烟</li>
* <li>吸烟者发出完成信号 &rarr 供应者将下一个组合放到桌子上</li>
* <b>互斥关系:</b>
* <li>三个吸烟者和供应者不能同时碰桌子(桌子是临界资源)</li>
*/
public class Smoker {
static final Semaphore[] offer
= new Semaphore[]{new Semaphore(0), new Semaphore(0), new Semaphore(0)};
static final Semaphore finish = new Semaphore(0);
static final Map<Integer, String> map = new HashMap<>();
static {
map.put(0, "纸和胶水");
map.put(1, "烟草和胶水");
map.put(2, "烟草和纸");
}
public static void main(String[] args) {
new Thread(()->{
int i = 0;
while (true) {
try {
offer[i].release();
System.out.println(Thread.currentThread().getName() + "把" + map.get(i) + "放在了桌子上");
i = (i +1) % 3;
finish.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "供应者").start();
for (int i = 0; i < 3; i++) {
int j = i;
new Thread(()->{
while (true) {
try {
offer[j].acquire();
System.out.println(Thread.currentThread().getName() + "从桌子上拿走了" + map.get(j) + "并开始吸烟");
finish.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "吸烟者" + j + "号").start();
}
}
}
读者-写者问题:
有读者和写者两组并发进程,共享一个文件,两个以上读进程同时访问文件不会产生副作用,但当某个写进程运行时,其他进程便不能运行了。
因而有以下要求:① 允许多个读者可以同时对文件进行读取。② 只允许一个写者往文件中写入信息。③ 写者工作时其他进程不的访问临界区。
import java.io.*;
import java.util.concurrent.Semaphore;
/**
* <b>互斥关系:</b>
* <li>读者-读者不存在互斥关系,写者-写者存在互斥关系。</li>
*/
public class ReaderAndWriter {
/* rw用来给文件资源上锁,w用来提高写进程的优先级,实现FCFS算法,避免饥饿。 */
static Semaphore rw = new Semaphore(1);
static Semaphore mutex = new Semaphore(1);
static Semaphore w = new Semaphore(1);
static int count = 0;
static String path;
public static void main(String[] args) {
path = "text.txt";
new Writer("Hello world!", "写者一").start();
new Writer("你好世界!", "写者二").start();
new Reader("读者一").start();
new Reader("读者二").start();
new Reader("读者三").start();
new Reader("读者四").start();
new Reader("读者五").start();
new Reader("读者六").start();
new Reader("读者七").start();
}
static class Writer extends Thread{
private final char[] arr;
synchronized void write(char c) {
try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path, true)))) {
writer.write(c);
System.out.println(Thread.currentThread().getName() + "写下了" + c);
writer.flush();
} catch (IOException e) {
System.err.println("写入时出现IO异常。");
}
}
public Writer(String str, String name) {
arr = str.toCharArray();
this.setName(name);
}
@Override
public void run() {
for (int i = 0; i < arr.length; i++) {
try {
w.acquire();
rw.acquire();
write(arr[i]);
rw.release();
w.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Reader extends Thread{
synchronized void read() {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)))) {
System.out.println(Thread.currentThread().getName() + "读出了" + reader.readLine());
} catch (IOException e) {
System.err.println("读取时出线IO异常");
}
}
public Reader(String name) {
super();
this.setName(name);
this.setDaemon(true);
}
@Override
public void run() {
try {
w.acquire();
mutex.acquire();
if (count == 0) {
/* 这里加的锁防小人不防君子,也就是对写着来说我说我这个所有用,对读者来说你说我这个没用。 */
rw.acquire();
}
count++;
/* 从mutex的p操作到v操作的这一段代码必须得是原子操作,mutex它的作用其实就相当于是一个synchronize块 */
mutex.release();
w.release();
read();
mutex.acquire();
count--;
if (count == 0) {
rw.release();
}
mutex.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
哲学家就餐问题:
哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。
哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。
首先我们先来看这样一串代码及其运行结果:
import java.util.concurrent.Semaphore;
以上是关于操作系统&java多线程技术几种信号量机制算法的主要内容,如果未能解决你的问题,请参考以下文章