Lock与synchronized是不一样的

很多编码者都会说,Lock类和synchronized关键字用在代码块的并发性和内存上时语义是一样的,都是保持代码块同时只有

一个线程具有执行权。这样的说法只对了一半,我们以一个任务提交给多个线程运行为例,来看看使用显示锁(Lock类)和

内部锁(synchronized关键字)有什么不同。首先定义一个任务:
import java.util.Calendar;

public class Task {

public void doSomething(){
	try {
		Thread.sleep(2000);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	StringBuffer sb = new StringBuffer();
	sb.append("线程名称:"+Thread.currentThread().getName());
	sb.append(",执行时间:"+Calendar.getInstance().get(13)+"s");
	System.out.println(sb);
}

}

显示锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class TaskWithLock extends Task implements Runnable{

private final Lock lock = new ReentrantLock();
@Override
public void run() {
	// TODO Auto-generated method stub
	try{
	lock.lock();
	doSomething();
	}finally{
		lock.unlock();
	}
}

}

内部锁任务
class TaskWithSync extends Task implements Runnable{

@Override
public void run() {
	// TODO Auto-generated method stub
	synchronized("A"){
		doSomething();
	}
}

}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

/**
 * @param args
 */
public static void main(String[] args) throws Exception{
	// TODO Auto-generated method stub

	runTasks(TaskWithLock.class);
	runTasks(TaskWithSync.class);
}

public static void runTasks(Class<? extends Runnable> clz) throws Exception{
	
	ExecutorService es = Executors.newCachedThreadPool();
	System.out.println("***开始执行"+clz.getSimpleName()+"任务****");
	for(int i=0;i<3;i++){
		es.submit(clz.newInstance());
	}
	TimeUnit.SECONDS.sleep(10);
	System.out.println("------"+clz.getSimpleName()+"任务执行完毕-----\n");
	es.shutdown();
}

}

开始执行TaskWithLock任务*
线程名称:pool-1-thread-1,执行时间:10s
线程名称:pool-1-thread-3,执行时间:10s
线程名称:pool-1-thread-2,执行时间:10s
------TaskWithLock任务执行完毕-----

开始执行TaskWithSync任务*
线程名称:pool-2-thread-1,执行时间:20s
线程名称:pool-2-thread-3,执行时间:22s
线程名称:pool-2-thread-2,执行时间:24s
------TaskWithSync任务执行完毕-----

注意看运行时间戳,显示锁是同时运行的,很显然在pool-1-thread-1线程执行到sleep时,其他两个线程也会运行到这里,

一起等待,然后一起输出,这还具有线程互斥的概念吗?
而内部锁的输出则是我们预期结果:pool-2-thread-1线程在运行时其他线程处于等待状态,pool-2-thread-1执行完毕后,

JVM从等待线程池中随机获得一个线程pool-2-thread-3执行,最后再执行pool-2-thread-2,这正是我们希望的。

Lock锁为什么不出现互斥情况呢?
这是因为对于同步资源来说(示例中是代码块),显示锁是对象级别的锁,而内部锁是类级别的锁,也就是说Lock锁是跟随

对象的,synchronized锁是跟随 类的,更简单地说把Lock定义为多线程的私有属性是起不到资源互斥作用的,除非把Lock定

义为所有线程的共享变量。

public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub

	final Lock lock = new ReentrantLock();
	for(int i=0;i<3;i++){
		new Thread(new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				
				try {
					lock.lock();
					Thread.sleep(2000);
					System.out.println(Thread.currentThread().getName());
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}finally{
					lock.unlock();
				}

				
			}
			
		}).start();
	}
}

线程名称Thread-0、Thread-1、Thread-2会逐渐输出,也就是一个线程在执行时,其他线程就处于等待状态。这里三个线程

运行的实例对象是同一个类(都是Client$1类的实例)。
(1)Lock支持更细粒度的锁控制
假设读写锁分离,写操作时不允许有读写操作存在,而读操作时读写操作可以并发执行,这一点内部锁就很难实现。显示锁

士例代码如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Foo {

//可重入的读写锁
private final ReentrantReadWriteLock rw1 = new ReentrantReadWriteLock();
//读锁
private final Lock r = rw1.readLock();
//写锁
private final Lock w = rw1.writeLock();
//读操作,可并发执行
public void read(){
	
	try {
		r.lock();
		Thread.sleep(1000);
		System.out.println("read......");
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally{
		r.unlock();
	}
}

//写操作,同时只允许一个写操作
public void write(Object _obj){
	
	try {
		w.lock();
		Thread.sleep(1000);
		System.out.println("writing......");
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally{
		w.unlock();
	}
}

}

(2)Lock是无阻塞锁,synchronized是阻塞锁
当线程A持有锁时,线程B也期望获得锁,此时,如果程序中使用的是显示锁,则B线程为等待状态(在通常的描述中,也认为

此线程被阻塞了),若使用的是内部锁则为阻塞状态。
(3)Lock可实现公平锁,synchronized只能是非公平锁
(4)Lock是代码级的,synchronized是JVM级的
Lock是通过编码实现的,synchronized是在运行期由JVM解释的,相对来说synchronized的优化可能性更高,毕竟是在最核心

部分支持的,Lock的优化则需要用户自行考虑。
显示锁和内部锁的功能各不相同,在性能上也稍有差别,但随着JDK的不断推进,相对来说,显式锁使用起来更加便利和强大

,在实际开发中选择哪种类型的锁就需要根据实际情况考虑了:灵活、强大则选择Lock,-快捷、安全则选择synchronized。

<think>好的,我现在需要回答用户关于Java数据结构中插入读取时使用同锁数量及并发控制的问题。首先,我得理解用户的具体需求。用户提到“插入读取加锁机制同,锁数量同”,这可能涉及到并发数据结构的设计,比如读写锁(ReadWriteLock)或更细粒度的锁机制。 接下来,我应该回忆Java中常用的并发数据结构。比如,ConcurrentHashMap使用了分段锁(Segment),在Java 8之后改为CASsynchronized结合的方式,这样同的段可以独立加锁,提高并发性。另外,CopyOnWriteArrayList则是在写入时复制整个数组,读取加锁,写入加锁,适合读多写少的场景。 然后,用户提到的“同锁数量”可能指的是在插入读取时使用的锁数量同。例如,ConcurrentHashMap的分段锁,每个段一个锁,插入时只需要锁住对应的段,而读取可能需要锁(取决于版本)。Java 8之后的ConcurrentHashMap使用Node作为锁单位,进一步细化锁粒度,这样并发度更高。 另外,读写锁ReentrantReadWriteLock也是一个关键点。读取可以共享锁,允许多个线程同时读,而写入时独占锁,阻塞其他读写操作。这适用于读多写少的情况,比如缓存。 还需要考虑其他数据结构,比如LinkedBlockingQueue,它使用两个锁(putLocktakeLock)分别控制插入移除操作,提高吞吐量。 现在需要整理这些内容,分点说明同的数据结构它们的锁机制,强调插入读取时锁的数量类型差异。同时,需要引用用户提供的参考中的锁粒度概念,比如表锁行锁,类比到Java中的同锁策略。 需要确保回答结构清晰,步骤明确,涵盖主要的数据结构及其并发控制机制,并回答用户可能的相关问题。最后生成的相关问题要围绕这些数据结构的应用场景、性能优化选择考量等方面。</think>### Java数据结构中插入读取的差异化加锁机制 在Java并发编程中,同数据结构通过差异化的锁机制实现高效的插入读取操作。以下是几种典型实现方式及其原理: #### 1. 读写锁(ReentrantReadWriteLock) - **机制**:将锁分为读锁(共享)写锁(独占) - **锁数量**: - 读操作:允许多线程共享读锁,锁数量=并发读取线程数 - 写操作:独占锁,锁数量=1 - **示例场景**:缓存系统 ```java ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); void readData() { lock.readLock().lock(); try { /* 读取操作 */ } finally { lock.readLock().unlock(); } } void writeData() { lock.writeLock().lock(); try { /* 写入操作 */ } finally { lock.writeLock().unlock(); } } ``` #### 2. 分段锁(ConcurrentHashMap) - **机制**:将数据分段管理(Java7实现) - **锁数量**: - 读操作:无锁(volatile读取) - 写操作:仅锁定当前段,锁数量=1(每个段独立锁) - **升级版**:Java8改用CAS+synchronized实现更细粒度锁 #### 3. 双锁队列(LinkedBlockingQueue) - **机制**:分离插入提取的锁控制 - **锁数量**: - 插入操作:putLock(1个) - 读取操作:takeLock(1个) - **吞吐量提升**:允许同时进行插入提取操作 #### 4. 写时复制(CopyOnWriteArrayList) - **机制**:写操作复制新数组 - **锁数量**: - 读操作:无锁 - 写操作:全局锁(1个) - **特点**:适合读多写少场景 $$ \text{并发度} = \frac{\text{有效操作时间}}{\text{临界区时间}} \times \text{锁粒度系数} $$ #### 选择依据 1. 读写比例(读多写少优先选读写锁) 2. 数据一致性要求(强一致性需更细粒度锁) 3. 性能要求(低延迟场景避免全局锁) [^1]: 参考锁粒度划分原则,类似数据库行锁表锁的选择逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

trxcsdn2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值