【Java面试题】如何保障同一资源被多个线程并发方位时的完整性?
2023-03-04 09:19:11
身为技术岗的企业,不仅要经过面试,还要进行一些书面测试。对“如何保证多个线程同时向同一资源同时发方向时的完整性?”进行整理是一个比较常见的问题。今日我们将与你们一起来学习这道考题的解答。
【JAVA考题】如何保证多个线程同时进行相同资源定向时的完整性?
通常使用信号或者加锁机制来实现同步,以保证任何时间最多只能访问一个线程。在多线程编程中,Java语言实现了完全对象化,为同步机制提供了很好的支持。
Java中支持synchronized的方法共有四种,前三种是synchronics和管道方法。不推荐使用管道方法,阻塞队列方法在问题4中已经介绍过,现在仅介绍前两种。
- wait()/notify()方法
- await()/signal()方法
- BlockingQueue阻塞队列方法
- PipedInputStream/PipedOutputStream
一、生产者类:
```
public class Producer extends Thread { //每次生产的产品数量
private int num;
//所在放置的仓库
private Storage storage;
//构造函数,设置仓库
public Producer(Storage storage) {
this.storage = storage;
}
//线程run函数
public void run() {
produce(num);
}
//调用仓库Storage的生产函数
public void produce(int num) {
storage.produce(num);
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Storage getStorage() {
return storage;
}
public void setStorage(Storage storage) {
this.storage = storage;
}
}
```
二、消费者类:
```
public class Consumer extends Thread { //每次消费的产品数量
private int num;
//所在放置的仓库
private Storage storage;
//构造函数,设置仓库
public Consumer(Storage storage) {
this.storage = storage;
}
//线程run函数
public void run() {
consume(num);
}
//调用仓库Storage的生产函数
public void consume(int num) {
storage.consume(num);
}
// get/set方法
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Storage getStorage() {
return storage;
}
public void setStorage(Storage storage) {
this.storage = storage;
}
}
```
仓库类:(wait()/notify()方法)
```
public class Storage { //仓库最大存储量
private final int MAX_SIZE = 100;
//仓库存储的载体
private LinkedList list = new LinkedList();
//生产num个产品
public void produce(int num) {
//同步代码段
synchronized (list) {
//如果仓库剩余容量不足
while (list.size() + num > MAX_SIZE) {
System.out.print("【要生产的产品数量】:" + num);
System.out.println("【库存量】:" + list.size() + "暂时不能执行生产任务!");
try {
list.wait();//由于条件不满足,生产阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//生产条件满足情况下,生产num个产品
for (int i = 1; i <= num; ++i) {
list.add(new Object());
}
System.out.print("【已经生产产品数】:" + num);
System.out.println("【现仓储量为】:" + list.size());
list.notifyAll();
}
}
//消费num个产品
public void consume(int num) {
//同步代码段
synchronized (list) {
//如果仓库存储量不足
while (list.size() < num) {
System.out.print("【要消费的产品数量】:" + num);
System.out.println("【库存量】:" + list.size() + "暂时不能执行生产任务!");
try {
//由于条件不满足,消费阻塞
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费条件满足情况下,消费num个产品
for (int i = 1; i <= num; ++i) {
list.remove();
}
System.out.print("【已经消费产品数】:" + num);
System.out.println("【现仓储)量为】:" + list.size());
list.notifyAll();
}
}
// get/set方法
public LinkedList getList() {
return list;
}
public void setList(LinkedList list) {
this.list = list;
}
public int getMAX_SIZE() {
return MAX_SIZE;
}
}
```
仓库类:(await()/signal()方法)
```
public class Storage { //仓库最大存储量
//仓库最大存储量
private final int MAX_SIZE = 100;
//仓库存储的载体
private LinkedList list = new LinkedList();
//锁
private final Lock lock = new ReentrantLock();
//仓库满的条件变量
private final Condition full = lock.newCondition();
//仓库空的条件变量
private final Condition empty = lock.newCondition();
//生产num个产品
public void produce(int num) {
//获得锁
lock.lock();
//如果仓库剩余容量不足
while (list.size() + num > MAX_SIZE) {
System.out.print("【要生产的产品数量】:" + num);
System.out.println("【库存量】:" + list.size() + "暂时不能执行生产任务!");
try {
//由于条件不满足,生产阻塞
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//生产条件满足情况下,生产num个产品
for (int i = 1; i <= num; ++i) {
list.add(new Object());
}
System.out.print("【已经生产产品数】:" + num);
System.out.println("【现仓储量为】:" + list.size());
//唤醒其他所有线程
full.signalAll();
empty.signalAll();
//释放锁
lock.unlock();
}
//消费num个产品
public void consume(int num) {
//获得锁
lock.lock();
//如果仓库存储量不足
while (list.size() < num) {
System.out.print("【要消费的产品数量】:" + num);
System.out.println("【库存量】:" + list.size() + "暂时不能执行生产任务!");
try {
//由于条件不满足,消费阻塞
empty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费条件满足情况下,消费num个产品
for (int i = 1; i <= num; ++i) {
list.remove();
}
System.out.print("【已经消费产品数】:" + num);
System.out.println("【现仓储)量为】:" + list.size());
//唤醒其他所有线程
full.signalAll();
empty.signalAll();
//释放锁
lock.unlock();
}
// set/get方法
public int getMAX_SIZE() {
return MAX_SIZE;
}
public LinkedList getList() {
return list;
}
public void setList(LinkedList list) {
this.list = list;
}上述解决方案是“如何保证多个线程同时定位相同资源方向的同时保持完整性?”请关注图灵java相关资讯页面,后面会有更多关于java面试的主题和解析。