一、Synchronized和Lock区别
1.Synchronized 是java内置的关键字;Lock是类
2.Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
3.Synchronized 会自动释放锁,Lock必须要手动释放锁,不释放会死锁
4.Synchronized 如果线程1(获得锁,阻塞)线程2(等待),lock不一定会等待下去
5.Synchronized 可重入锁,不可以中断,是非公平的,Lock 可重入锁,可判断锁,非公平(可以自己设置)
6.Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码
线程之间的通信问题:生产者和消费者问题!等待唤醒,通知唤醒
线程交替执行,AB操作同一个变量num =0,先执行num加一才能执行num减一
Anum+1
Bnum-1
如果上面不是A B 而是A B C D 就会出现线程安全问题(虚假唤醒)由if造成的
解决:把if改成while
4、生产者和消费者问题
面试必会:单例模式、排序算法、生产者和消费者、死锁
生产者和消费者问题Synchronized版
两种对比如下图
第二种:Lock juc
任何一个新的技术,绝对不是仅仅只是覆盖了原来的技术,优势和补充
Condition 精准的通知和唤醒线程
问题?目前结果是随机的状态,我想要 有序执行ABCD四个线程
A执行完调用B,B执行完调用C,C执行完调用D
condition实现顺序执行,先执行1,唤醒2,执行2,唤醒3,执行3,唤醒1
如何判断锁的是谁永远的知道什么锁
锁到底锁的是谁 1.对象 2.Class
ArrayList安全问题:
当加入线程后报ConcurrentModificationException问题
方案一:
List a = new ArrayList<>();改为
List a = new Vector<>();
底层代码:
封装的方法已经有处理。
方案二:
public static void main(String[] args) {
// List<String> a = new Vector<>();
List<String> a = Collections.synchronizedList(new ArrayList<>());//方案二
for (int i = 0; i < 10; i++) {
new Thread(() -> {
a.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(a);
}, String.valueOf(i)).start();
}
}
方案三:采用JUC(java.util.concurrent)
package com.example.demo;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class Pja {
public static void main(String[] args) {
// List<String> a = new Vector<>();
// List<String> a = Collections.synchronizedList(new ArrayList<>());
List<String> a = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
a.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(a);
}, String.valueOf(i)).start();
}
}
}
CopyOnwrite写入时复制cow计算机程序设计领域的一种优化策略;
多个线程调用的时候,List,读取的时候,固定的,写入(覆盖)
在写入的时候避免覆盖,造成数据问题!
CopyOnWriteArrayList 比 Vector牛逼在哪里?
CopyOnWriteArrayList 没有用synchronized,用了synchronized会降低效率。
CopyOnWriteArrayList 内是Lock锁实现。Vector是synchronized实现。
set 和list一样,也存在线程安全问题。也是同样的方法解决。
set是什么?他就是map。set add方法就是map的put方法。
Map<String, String> objectObjectHashMap = new ConcurrentHashMap<>();//区别于平常的map,平常的map会出现安全问题报错
for(int i=1;i<30;i++){
new Thread(()->{
objectObjectHashMap.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));
System.out.println(objectObjectHashMap);
},String.valueOf(i)).start();
}
细节:
1、有缓存
2、结果可能需要等待,会阻塞!
1.CountDownLatch
一种同步帮助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。 必须要执行任务的时候,再使用!
2.CyclicBarrier
个同步帮助,允许一组线程相互等待,以达到一个共同的障碍点。cyclicbarriers涉及一个固定大小的线程必须党偶尔互相等待程序是有用的。该障碍被称为循环,因为它可以在等待线程被释放后重新使用。
一个CyclicBarrier支持一个可选的Runnable命令,每个障碍点一次,在聚会的最后一个线程到达后,但在任何线程释放。这种障碍作用是有用的更新共享状态之前,任何一方继续。
3.信号量Semaphore(并发用的较多)
以上三个常用辅助类(必会)
读写锁ReadwriteLock 只能写一次,可以多次读,区别于Lock和async**更能体现它的特性
阻塞队列