Java 独占锁|共享锁|互斥锁

时光怂恿深爱的人放手 提交于 2020-02-23 00:10:24

独占锁

又叫写锁,指该锁只能被一个线程所持有。Java 中 ReentrantLock 和 synchronized 都是独占锁。

共享锁

又叫读锁,指该锁可以被多个线程所持有。Java 中 ReentrantReadWriteLock 其读锁是共享锁,其写锁是独占锁。

读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。

互斥锁

在访问共享资源之前对进行加锁操作,在访问完成之后进行解锁操作。 加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前进程解锁。

加锁前

代码

import java.util.HashMap;
import java.util.Map;

// 模拟缓存操作
class MyChahe{
	private volatile Map<String, Object> map = new HashMap<>();
	
	public void put(String key, Object value) {
		System.out.println(Thread.currentThread().getName()+"\t 准备写... "+key+" "+value);
		try {
			// 停一会
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		map.put(key, value);
		System.out.println(Thread.currentThread().getName()+"\t 写完成...");
	}
	
	public Object get(String key) {
		System.out.println(Thread.currentThread().getName()+"\t 准备读...");
		try {
			// 停一会
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		Object object = map.get(key);
		System.out.println(Thread.currentThread().getName()+"\t 读完成... "+object);
		return object;
	}
}

public class ReadWriteLockDemo {
	public static void main(String[] args) {
		MyChahe myChahe = new MyChahe();
		for (int i = 1; i <= 3; i++) {
			final int tmpInt = i;
			new Thread(()->{
				myChahe.put(tmpInt+"", tmpInt+"");
			},String.valueOf(i)).start();
			
		}
		for (int i = 1; i <= 3; i++) {
			final int tmpInt = i;
			new Thread(()->{
				myChahe.get(tmpInt+"");
			},String.valueOf(i)).start();
			
		}
	}
}

运行结果

从运行结果中可以看出,1线程再写入的时候被 2 线程打断,而 2 线程再写入的时候被 3 线程也打断了,最终导致都写入失败了。正常的执行结果应该是 写入->写入成功,中间不允许打断,于是我们给上面的程序进行加锁操作。

加锁后

代码

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyChahe{
	private volatile Map<String, Object> map = new HashMap<>();
	// 读写锁
	private ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
	
	public void put(String key, Object value) {
		try {
			rwlock.writeLock().lock();
			System.out.println(Thread.currentThread().getName()+"\t 准备写... "+key+" "+value);
			try {
				// 停一会
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			map.put(key, value);
			System.out.println(Thread.currentThread().getName()+"\t 写完成...");
		} catch (Exception e) {
			System.out.println(e);
		}finally {
			rwlock.writeLock().unlock();
		}
	}
	
	public Object get(String key) {
		try {
			rwlock.readLock().lock();
			System.out.println(Thread.currentThread().getName()+"\t 准备读...");
			try {
				// 停一会
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			Object object = map.get(key);
			System.out.println(Thread.currentThread().getName()+"\t 读完成... "+object);
			return object;
		} catch (Exception e) {
			System.out.println(e);
		}finally {
			rwlock.readLock().unlock();
		}
		return null;
		
	}
}

public class ReadWriteLockDemo {
	public static void main(String[] args) {
		MyChahe myChahe = new MyChahe();
		for (int i = 1; i <= 3; i++) {
			final int tmpInt = i;
			new Thread(()->{
				myChahe.put(tmpInt+"", tmpInt+"");
			},String.valueOf(i)).start();
			
		}
		for (int i = 1; i <= 3; i++) {
			final int tmpInt = i;
			new Thread(()->{
				myChahe.get(tmpInt+"");
			},String.valueOf(i)).start();
			
		}
	}
}

运行结果

加锁后运行的结果一致了,写操作不可以被其他线程打断,读操作可以同时多个线程同时读取。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!