JUC
进程和线程
进程:一个程序,QQ,微信,
一个进程至少包含一个线程,可以有多个线程
java默认有2个线程。main线程和GC线程
线程:
Java: Thread Runable Callable
java无法直接开启线程,是用的本地方法开启的。
并发和并行
并发:多个线程操作同一个资源。单核CPU
并行:多个人一起行走。多个CPU
并发编程的的本质:充分利用CPU的资源
线程
线程的状态
新生、运行、阻塞、等待(死等)、超时等待、终止
wait和sleep的区别
1.来自不同的类,Object.wait Thread.sleep
TimeUnit.SECONDS.sleep(1000);//睡1000秒
2.关于锁的释放
wait会释放锁
sleep抱着锁睡觉,不会释放锁
3.使用的范围是不同的
wait只能在同步代码块中使用
sleep可以在任何地方使用
4.是否需要唤醒
wait需要被唤醒 notify
sleep到时自动唤醒
Lock
传统Synchronize
synchronize 本质:队列,锁
Lock接口
三个实现类:
ReentrantLock 普通可重入锁
ReentrantReadWriteLock.ReadLock 读锁
ReentrantReadWriteLock.writeLock 写锁
Lock lock = new ReentrantLock();默认是非公平锁
Lock lock = new ReentrantLock(true);公平锁
公平锁:十分公平,排队获取锁
为什么默认不是公平锁。如果两个任务 一个3h,一个3s。3s排在3h后面的话就要等3小时才能获取到锁。
非公平锁:可以插队,synchronize也是非公平锁
Lock和synchronize的区别
1.synchronize是一个关键字,Lock是一个接口
2.synchronize无法获取到锁状态,Lock可以判断是否获取到了锁
3.synchronize是全自动的,会自动释放锁。Lock需要手动解锁
4.synchronize 线程1获得锁之后线程2会一直等待;Lock不一定会等待下去。tryLock
5.synchronize 可重入,非公平,不可中断;Lock 可重入锁,可以自己设置公平不公平,可以判断锁
6.synchronize 适合锁少量的代码块,Lock适合锁大量的代码块
锁是什么,如何判断锁是谁的?
这里的synchronized锁的是调用该方法的对象
pubicl void synchronized test(){
...
}这里的synchronized锁锁的是当前类
pubicl static void synchronized test(){
...
}
集合
对集合并发操作,会出现ConcurrentModificationException 并发修改异常
List
解决并发修改异常的方法
- 1. Collections.synchronizedList() -- synchronized (mutex) {list.add(index, element);}
- 2. new CopyOnWriteArrayList<>();-- 用的lock锁,写时复制,每次新增一个元素时,直接复制以前的元素到新的一个list
- 3.new Vector<>(); 最早出现jdk1.0 直接锁整个方法,效率差
Set
Collections.synchronizedSet(new HashSet<>());
HashSet
实际上就是一个hashmap
public HashSet() {
map = new HashMap<>();
}
add方法就是put一个key。value是固定的
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Map
Collections.synchronizedMap(new HashMap<>());
new ConcurrentHashMap<>(); //推荐使用
new Hashtable<>();
callable
callable特点
1.有缓存
2.通过futuretask.get()阻塞,并获取结果
public class CallableTest {
public static void main(String[] args) throws Exception{
FutureTask futureTask = new FutureTask(()->{
System.out.println(123);
return "123";
});
new Thread(futureTask,"A").start();
new Thread(futureTask,"B").start(); //只会打印一遍123,取得是缓存
futureTask.get();
}
}
class MyThread implements Callable{
@Override
public String call() throws Exception {
return "123";
}
}
读写锁
队列
[图片上传失败...(image-bf7888-1642649477663)]
启动多少个线程
CPU密集型和IO密集型
CPU密集型:根据CPU核心数来,跟CPU核心数保持一致最好
IO密集型:设置2倍io任务数
四大函数式接口
Lamab 链式编程 函数式接口 stream流式计算
函数式接口:只有一个方法的接口 ,只要是函数式接口就可以用lamab简化,实际上是匿名内部类
@FunctionalInterface
public interface Runnable {
public abstract void run();
}foreach()//需要一个consumer函数式接口参数
[图片上传失败...(image-904e85-1642649477663)]
函数型Function 传入一个参数T返回一个类型R
断定型 传入一个参数,返回一个boolean
消费型Consumer 传入一个参数,没有返回值
供给型Supplier 没有参数,返回一个对象
Stream流式计算