Java生态中线程安全的思考
1.公平锁、非公平锁
概念:公平与非公平的意思是服务器对不同时间段发来的获取同一个锁的请求,先后获得锁是否是否按照先来后到的顺序获取锁的。
非公平锁看似根本就不该存在对吗?其实他有他存在的意义,比如说,大家买车票、打饭等待排队时通常有工作人员维持秩序,以防某些素质不高的人破坏秩序,cpu也是一样,挂起或恢复线程维持锁的公平性是需要消耗cpu资源的。
2.可重入锁(递归锁)
顾名思义,就是可重入的,在获得同一个对象的锁前提下进入某一方法的内部加锁方法是被允许且优先的,一定程度上可避免死锁。
3.死锁
死锁就是导致程序阻塞、停止无限等待的锁,白话说就是线程们都要获取其他线程占有的锁
典型案例《哲学家就餐问题》,五位哲学家在餐桌上不是在思考就是在吃饭,每个人的左右手边都放了一根筷子,注意只有一根哦,每个人都紧紧的握住自己的那根筷子,并试图从旁边的人获得另一根筷子以便夹菜吃饭,如果没有人跟退让,那么这个时候就会产生死锁问题。
《高性能Mysql第三版1.3.2》描述事务对死锁的解释,概念其实差不多:
死锁代码验证:
class Resource implements Runnable{
private String lock1;
private String lock2;
public Resource(String lock1,String lock2) {
this.lock1 = lock1;
this.lock2 = lock2;
}
@Override
public void run() {
synchronized (lock1) {
System.out.println("鎖住了"+lock1+"还要锁lock2");
try {
TimeUnit.SECONDS.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("鎖住了"+lock2);
}
}
}
}
/**
* 死锁代码验证 多个线程同时锁住多个资源不释放导致的。
* 异常查找命令:
* windows环境 jps查看进程pid
* jstack pid 查看跟踪栈信息
* @author DETBG23
*
*/
public class DeadLockDemo {
public static void main(String[] args) {
String lock1 = "1";
String lock2 = "2";
Resource resource = new Resource(lock1,lock2);
Resource resource2 = new Resource(lock2,lock1);
new Thread(resource).start();
new Thread(resource2).start();
}
}
``
#### synchronized
非公平锁、可重入锁,Java自带的关键字,底层是封装好的native方法,不需要手动解锁,用在普通方法上锁的是this,用在静态方法上锁的是Class对象锁粒度大。
#### JUC之Lock
Java1.5发布的并发包下的API级别的锁,手动加锁解锁,锁的伸缩性强,可根据我们的需要锁住相应的代码片段,不同强行占用其他资源。且可以通过Conditon实现精确的线程间通信。
Lock接口的实现:
1)ReentrantLock
2)ReentrantReadWriteLock:读共享,写独占,提高并发能力
class MyCache{
private volatile Map<String, Object> map = new HashMap();
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void put(String key,Object val) throws InterruptedException {
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"正在写入"+key);
Thread.sleep(300);
map.put(key, val);
System.out.println(Thread.currentThread().getName()+"写入完成");
} finally {
rwLock.writeLock().unlock();
}
}
public void get(String key) throws InterruptedException {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"正在读取"+key);
Thread.sleep(300);
map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完成");
} finally {
rwLock.readLock().unlock();;
}
}
public Map<String, Object> getHashMap() {
return map;
}
}
public class ReentRWLock {
public static void main(String[] args) throws InterruptedException {
Mycache mycache = new Mycache();
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
try {
mycache.put(temp+"", 0);
} catch (InterruptedException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
try {
mycache.get(temp+"");
} catch (InterruptedException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
Thread.sleep(900);
System.out.println(mycache.getHashMap());
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191105201749221.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDIyNjc1,size_16,color_FFFFFF,t_70)