操作系统之进程同步
1.什么是进程同步,为什么要引入进程同步?
- 进程同步是指多个进程在执行次序上进行协调,使它们按一定的规则共享资源和相互合作。引入进程同步是为了避免并发进程因资源竞争而产生数据不一致、混乱等问题,确保系统的稳定性和正确性。
2.同步机制应该遵循的原则是什么?为什么要遵循这些原则(可以通过举例进行解释)
- 同步机制应遵循空闲让进、忙则等待、有限等待和让权等待原则。空闲让进可提高资源利用率,如空闲文件允许多线程写入;忙则等待防数据混乱,像多线程改数据库;有限等待避“饥饿”,保证进程执行;让权等待免忙等,使系统高效运行。
3.什么是信号量,为什么引入信号量机制?
- 信号量是一个整型变量,用于进程同步。它有两个原子操作:P操作(等待)和V操作(释放)。引入信号量机制是为了有效解决进程同步和互斥问题,通过对信号量的操作来控制进程对临界资源的访问,避免因竞争导致的数据不一致等问题。
4.给出记录型信号量wait()和signal()操作的实现代码
import java.util.LinkedList;
import java.util.Queue;
class RecordSemaphore {
//信号量
private int value;
//阻塞队列
private Queue<Thread> queue;
public RecordSemaphore(int value) {
this.value = value;
this.queue = new LinkedList<>();
}
public synchronized void waitOp() {
value--;
if (value < 0) {
try {
queue.add(Thread.currentThread());
// 线程在 RecordSemaphore 对象的监视器上等待
this.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public synchronized void signalOp() {
value++;
if (value <= 0) {
queue.poll();
// 在 RecordSemaphore 对象的监视器上唤醒等待的线程
this.notify();
}
}
public static void main(String[] args) {
RecordSemaphore semaphore = new RecordSemaphore(1);
// 创建线程 1
Thread thread1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 尝试获取信号量");
semaphore.waitOp();
System.out.println(Thread.currentThread().getName() + " 已获取信号量,正在执行操作...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 操作完成,释放信号量");
semaphore.signalOp();
}, "Thread-1");
// 创建线程 2
Thread thread2 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 尝试获取信号量");
semaphore.waitOp();
System.out.println(Thread.currentThread().getName() + " 已获取信号量,正在执行操作...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 操作完成,释放信号量");
semaphore.signalOp();
}, "Thread-2");
// 创建线程 3
Thread thread3 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 尝试获取信号量");
semaphore.waitOp();
System.out.println(Thread.currentThread().getName() + " 已获取信号量,正在执行操作...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 操作完成,释放信号量");
semaphore.signalOp();
}, "Thread-3");
// 启动线程
thread1.start();
thread2.start();
thread3.start();
// 等待线程执行完成
try {
thread1.join();
thread2.join();
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有线程执行完毕");
}
}
运行结果1:
Thread-1 尝试获取信号量
Thread-1 已获取信号量,正在执行操作...
Thread-3 尝试获取信号量
Thread-2 尝试获取信号量
Thread-1 操作完成,释放信号量
Thread-3 已获取信号量,正在执行操作...
Thread-3 操作完成,释放信号量
Thread-2 已获取信号量,正在执行操作...
Thread-2 操作完成,释放信号量
所有线程执行完毕
运行结果2:
Thread-1 尝试获取信号量
Thread-1 已获取信号量,正在执行操作...
Thread-2 尝试获取信号量
Thread-3 尝试获取信号量
Thread-1 操作完成,释放信号量
Thread-2 已获取信号量,正在执行操作...
Thread-2 操作完成,释放信号量
Thread-3 已获取信号量,正在执行操作...
Thread-3 操作完成,释放信号量
运行结果3:
Thread-2 尝试获取信号量
Thread-2 已获取信号量,正在执行操作...
Thread-3 尝试获取信号量
Thread-1 尝试获取信号量
Thread-2 操作完成,释放信号量
Thread-3 已获取信号量,正在执行操作...
Thread-3 操作完成,释放信号量
Thread-1 已获取信号量,正在执行操作...
Thread-1 操作完成,释放信号量
所有线程执行完毕
5.用wait(),signal()操作尝试实现司机和售票员进程的同步(利用信号量实现前驱关系)
import java.util.LinkedList;
import java.util.Queue;
class RecordSemaphore {
// 信号量
private int value;
// 阻塞队列
private Queue<Thread> queue;
public RecordSemaphore(int value) {
this.value = value;
this.queue = new LinkedList<>();
}
public synchronized void waitOp() {
value--;
if (value < 0) {
try {
queue.add(Thread.currentThread());
// 线程在 RecordSemaphore 对象的监视器上等待
this.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public synchronized void signalOp() {
value++;
if (value <= 0) {
queue.poll();
// 在 RecordSemaphore 对象的监视器上唤醒等待的线程
this.notify();
}
}
public static void main(String[] args) {
// 用于控制售票员线程开始的信号量,初始值为 1 表示可以开始
RecordSemaphore conductorSemaphore = new RecordSemaphore(1);
// 用于控制司机线程开始的信号量,初始值为 0 表示需要等待
RecordSemaphore driverSemaphore = new RecordSemaphore(0);
// 创建售票员线程
Thread conductor = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 尝试获取信号量");
conductorSemaphore.waitOp();
System.out.println(Thread.currentThread().getName() + " 已获取信号量,正在执行操作...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 操作完成,释放信号量");
conductorSemaphore.signalOp();
// 售票员操作完成后,释放司机线程的信号量
driverSemaphore.signalOp();
}, "售票员");
// 创建司机线程
Thread driver = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 等待售票员完成操作...");
// 等待售票员线程释放信号量
driverSemaphore.waitOp();
System.out.println(Thread.currentThread().getName() + " 尝试获取信号量");
conductorSemaphore.waitOp();
System.out.println(Thread.currentThread().getName() + " 已获取信号量,正在执行操作...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 操作完成,释放信号量");
conductorSemaphore.signalOp();
}, "司机");
// 启动线程
conductor.start();
driver.start();
// 等待线程执行完成
try {
conductor.join();
driver.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有线程执行完毕");
}
}
测试结果如下:
售票员 尝试获取信号量
司机 等待售票员完成操作...
售票员 已获取信号量,正在执行操作...
售票员 操作完成,释放信号量
司机 尝试获取信号量
司机 已获取信号量,正在执行操作...
司机 操作完成,释放信号量
所有线程执行完毕