【Java面试题】如何保障同一资源被多个线程并发方位时的完整性?

发布时间:2021-12-19 13:45:20

  身为技术岗的企业,不仅要经过面试,还要进行一些书面测试。对“如何保证多个线程同时向同一资源同时发方向时的完整性?”进行整理是一个比较常见的问题。今日我们将与你们一起来学习这道考题的解答。

  【JAVA考题】如何保证多个线程同时进行相同资源定向时的完整性?

  通常使用信号或者加锁机制来实现同步,以保证任何时间最多只能访问一个线程。在多线程编程中,Java语言实现了完全对象化,为同步机制提供了很好的支持。

  Java中支持synchronized的方法共有四种,前三种是synchronics和管道方法。不推荐使用管道方法,阻塞队列方法在问题4中已经介绍过,现在仅介绍前两种。

Java面试

  - 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面试的主题和解析。

上一篇 【Java面试题】经典Java面试题分享
下一篇 【Java面试题】Java开发工程师面试题分享