「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
静态同步方法锁的是当前类
非静态同步方法锁的是当前对象
8锁的本质是要判断锁的对象是什么
synchronized锁的不只是一个方法,而是锁的是这个方法所在的对象,同一时间只有一个线程进入
package com.lemon;
import java.util.concurrent.TimeUnit;
public class Lesson4_8Lock {
public static void main(String[] args) throws InterruptedException {
//后面的判断都是建立了在 Thread.sleep(100);的情况下此时有足够的时间让A线程先启动
//1.两个标准synchronized方法 先sendEmail还是sendSMS? 先sendEmail
//2.邮件方法暂停2秒,先邮件还是先短信 ? 邮件 因为sleep不会释放锁,同一时间只能有一个线程调用一个对象里面的同步方法
//3.新增一个普通方法?x先打印邮件还是hello ?hello 普通方法和同步锁无关
//4.两部手机先邮件还是先短信?先短信 这个时候两个对象对应的是两把锁,虽然A先启动但是sendEmail方法睡眠了2秒,所以B线程的sendSMS先打印
//5.两个静态同步方法,一个手机,先打印邮件还是短信? 先打印邮件,锁的是同一个类
//6.两个静态同步方法,两个手机,先打印邮件还是短信? 先打印邮件,锁的是同一个类
//7. 1个普通同步方法,一个静态同步方法,一个手机,先打印的是邮件还是短信? 不是一个锁,一个类锁一个对象锁 先打印短信
//8. 1个普通同步方法,一个静态同步方法,两个手机,先打印的是邮件还是短信?不是一个锁,一个类锁一个对象锁 短信
Phone phone = new Phone();
Phone phone2=new Phone();
new Thread(()->{
try {
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
//让主线程sleep100毫秒
Thread.sleep(100); //此时保证了A线程先启动
new Thread(()->{
try{
//phone.hello();
// phone2.sendSMS();
phone2.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
class Phone{ //资源类
public synchronized void sendEmail(){
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("send email~~~~~~~");
}
public static synchronized void sendSMS(){
System.out.println("send SMS~~~~~~~~");
}
public void hello(){
System.out.println("hello ~~~~~~~~~");
}
}
list不安全
public class Lesson5_ListNotSafe {
public static void main(String[] args) {
//Exception in thread "19" Exception in thread "24" Exception in thread "14" java.util.ConcurrentModificationException
//线程不安全
// List<String> list=new Vector<>(); //1.Vector线程安全但是性能不好 查看源码可以看到add方法加锁
List<String> list=new CopyOnWriteArrayList<>(); //3.CopyOnWriteArrayList
//2.List<String> list1 = Collections.synchronizedList(list); //juc中Collections工具类提供了方法
for(int i=1;i<=30;i++){
new Thread(()->{
list .add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
Vector 1读1写 性能低
ArrayList 读写提升,数据一致性下降
CopyOnWirteArrayList 写时复制读写分离
先clone一份,写完再合并
CopyOnWirteArrayList 的add方法源码解析
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray(); //添加一个对象的时候想复制一个数组
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;//向新数组中添加元素
setArray(newElements); //将原来的索引指向新的元素
return true; //这样做的好处是可以对CopyOnWrite容器进行并发的读而不需要加锁
} finally {
lock.unlock();
}
HashSet到底层是HashMap
public HashSet() {
map = new HashMap<>();
}
HashSet丢进去的元素就是Key,Value是写死的Object的常量
HashMap线程不安全
HashMap底层是数组链表加红黑树
hashMap里面存的是Node
默认为0初始化为16负载因子为0.75
new HashMap(16,0.75)
hashMap优化:
直接设置一个比较大的初始值,比,避免了频繁扩容
new HashMap<>(1000)直接设置初始值
new HashMap();