写一个固定容量的同步容器,拥有put方法和get方法,以及getCount方法,能够支持2个生产者线程以及10个消费者线程的阻塞调用。

本文深入解析自定义Java并发容器MyContainer的实现原理,包括使用ReentrantLock、Condition控制生产者和消费者线程的同步,以及与Java标准库中LinkedBlockingQueue、ArrayBlockingQueue的对比分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.example.demo.test;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyContainer<T> {
	final private LinkedList<T> list = new LinkedList<>();
	final private int MAX = 10;//最多10个元素

	private Lock lock = new ReentrantLock();
	private Condition producer = lock.newCondition();//生产者条件
	private Condition consumer = lock.newCondition();//消费者条件

	public void put(T t){
		try {
			lock.lock();
			while (list.size() == MAX){
				producer.await();//在这个条件下,生产者线程全部等待
			}
			list.add(t);
			consumer.signalAll();//通知消费者线程可以进行消费
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}

	public T get(){
		T t = null;
		try {
			lock.lock();
			while (list.size() == 0){
				consumer.await();//在这个条件下,消费者线程全部等待
			}
			t = list.removeFirst();
			producer.signalAll();//通知生产者可以进行生产
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
		return t;
	}

	public static void main(String[] args) {
		MyContainer<String> container = new MyContainer<>();
		//启动消费者线程
		for (int i = 0;i < 10;i++){
			new Thread(()->{
				for(int j = 0;j < 5; j++){
					System.out.println(container.get());
				}
			},"consumer"+i).start();
		}

		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		//启动生产者线程
		for (int i = 0;i < 2;i++){
			new Thread(()->{
				for (int j = 0;j < 25;j++){
					container.put(Thread.currentThread().getName()+"->"+j);
				}
			},"producer"+i).start();
		}
	}
}

其实java中已经有提供的阻塞式容器:如LinkedBlockingQueue(无界队列),提供了put和take方法用来添加和获取,如果容器满了或空了时调用方法就会进入阻塞。

ArrayBlockingQueue<>(10)  (有界队列:队列中装的元素是有限的)

添加的方法区别:

1、add():如果满了,会抛异常

2、put():如果满了,进入阻塞

3、offer():有boolean返回值,添加成功true,失败false

 

面试常问:Queue与List的区别?

Queue提供了对线程友好对API  如:offer  peek  poll等方法

BlockingQueue的put take阻塞方法

<think>好的,我现在需要回答用户的问题:如何在一个类中实现私有变量count的自增方法getCount方法,同时保证读安全。首先,我得理解用户的需求。他们希望确保在多线程环境下,对count的读是安全的,也就是说,当多个线程同时调用自增方法getCount时,不会出现数据不一致的问题。 首先,私有变量count应该是私有的,这样外部无法直接访问,只能通过公共方法来操作。自增方法需要原子性地增加count的值,而getCount方法需要安全地读取当前值。在Java中,处理多线程安全通常有几种方法:synchronized关键字、Lock接口、原子变量类(如AtomicInteger)等。 用户提到“读安全”,可能指的是在并发环境下,读操作都不会导致数据竞争或不一致。这时候,我需要考虑不同的同步机制。比如,使用synchronized方法或块来保证同一时间只有一个线程能访问这些方法。或者使用AtomicInteger,它内部通过CAS(Compare and Swap)操作来保证原子性,这样自增读取都是线程安全的,无需额外的同步。 接下来,我需要考虑哪种方法更适合用户的场景。如果用户的应用场景中,自增操作非常频繁,使用AtomicInteger可能更高效,因为它的实现基于硬件级别的原子操作,减少了线程上下文切换的开销。而如果除了自增读取之外还有其他复杂的操作需要同步,可能使用synchronized会更灵活。 然后,我需要编示例代码。如果使用synchronized,自增方法getCount方法都需要加上synchronized关键字,确保同一时间只有一个线程能执行这些方法。例如: public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } 这样,每次调用increment或getCount时,线程必须获得对象的内置锁,保证了原子性可见性。但这种方法在高度并发的情况下可能会有性能问题,因为线程需要竞争锁。 另一种方法是使用AtomicInteger: import java.util.concurrent.atomic.AtomicInteger; public class Counter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } } AtomicInteger的incrementAndGet()get()方法都是原子操作,内部使用CAS,避免了锁的开销,适合高并发场景。 用户可能需要知道这两种方法的区别以及适用场景。此外,还需要解释为什么这些方法能保证线程安全。例如,synchronized通过互斥锁保证同一时间只有一个线程执行方法,而AtomicInteger通过CAS操作保证原子性,同时利用volatile变量的可见性。 另外,需要考虑可见性问题。在synchronized方法中,进入退出同步块会分别获取释放锁,这保证了变量的修改对其他线程立即可见。而AtomicInteger内部使用volatile变量,确保了可见性。 可能还需要提到,如果只是简单的自增读取,AtomicInteger是更好的选择,因为它更高效。但如果方法中有更复杂的逻辑需要同步,可能需要使用synchronized或其他锁机制。 最后,需要检查是否有遗漏的情况,比如是否有可能出现竞态条件,或者是否需要使用volatile关键字。在synchronized的情况下,由于锁的获取释放已经保证了可见性,所以不需要额外使用volatile。而AtomicInteger内部已经处理了可见性问题,所以也不需要。 总结一下,回答应该包括两种实现方式,解释它们的原理,以及适用场景,确保用户理解如何选择合适的方法来保证线程安全。 </think> 在 Java 中,可以通过 **线程同步** 或 **原子类** 实现 `count` 的读安全。以下是两种常见方案: --- ### 方案 1:使用 `synchronized` 关键字(线程同步) ```java public class SafeCounter { private int count = 0; // 自增方法线程安全) public synchronized void increment() { count++; } // 读取方法线程安全) public synchronized int getCount() { return count; } } ``` **原理**: - `synchronized` 确保同一时间只有一个线程能访问 `increment()` 或 `getCount()` 方法。 - 互斥锁机制保证操作的原子性可见性。 --- ### 方案 2:使用 `AtomicInteger`(原子类) ```java import java.util.concurrent.atomic.AtomicInteger; public class SafeCounter { private AtomicInteger count = new AtomicInteger(0); // 自增方法线程安全) public void increment() { count.incrementAndGet(); } // 读取方法线程安全) public int getCount() { return count.get(); } } ``` **原理**: - `AtomicInteger` 内部通过 **CAS(Compare-And-Swap)** 操作实现原子性,无需显式同步。 - 底层依赖硬件指令,性能优于 `synchronized`。 --- ### 关键点总结 1. **原子性**:确保 `count++`(读-改-)操作不可分割。 2. **可见性**:线程对 `count` 的修改对其他线程立即可见。 3. **有序性**:禁止指令重排序导致的数据不一致。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值