JUC-多线程
2020-06-28 10:50:22 1 举报
AI智能生成
JUC
作者其他创作
大纲/内容
并发集合类
Collection
List
vector 不推荐使用已废弃
Conllections.synchronizedList 效率低
CopyOnwriterArrayList Lock锁实现
COW策略
Set
Collections.synchronizedSet 效率低
CopyOnwriteArraySet
Queue
阻塞队列:BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
同步队列
队列中只允许存储一个元素
AbstractQueue
四组API
抛出异常
添加:add()
删除:remove()
判断队首:element()
不抛出异常有返回值
添加:offer()
删除:poll()
判断队首:peek()
阻塞等待
添加:put()
删除:take()
超时等待
删除:pool()
双端队列:Deque
Map
HashMap
Collections.synchronizedMap
ConcurrentHashMap
常用辅助类
CountDownLatch
构造器 CountDownLatch(int index); // index 为计数器初始值
原理
CountDownLatch.DownLatch(); //计数器减一
CountDownLatch.await;当计数器为0时才开时向下执行
CyclicBarrier
加法计数器
Semaphore
线程通行证
构造器:Semaphore semaphore = new Semaphore(int index); // index为最大线程数
semaphore.acquire(); 获得 ,假如线程已经满了,就等待有空位为止
semaphore.release();释放,会将当前的信号量释放 +1,然后唤醒等待的线程
ReadWriteLock
写锁:一次只能被一个线程占用
创建锁:ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
上锁:readWriteLock.writeLock().lock();
解锁:readWriteLock.writeLock().unlock();
读锁:可以被多个线程占用
上锁:readWriteLock.readLock().lock();
解锁:readWriteLock.readLock().unlock();
线程池
三大方法
Executors.newSingleThreadExecutor()
只包含单个线程的线程池
Executors.newFixedThreadPool(5)
自定义线程数量的线程池
Executors.newCachedThreadPool()
可伸缩的线程池
不推荐使用
七大参数
corePoolSize:核心线程池大小
maximumPoolSize:核心线程池最大核心数
keepAliveTime:线程经过多久没被调用就被释放
TimeUnit:超时单位
BlockingQueue<Runnable>:消息队列
ThreadFactory:线程工厂
RejectedExecutionHandler:拒绝策略
四种拒绝策略
AbortPolicy
java.util.concurrent.RejectedExecutionException
CallerRunsPolicy
不会抛出异常
队列满了,从哪来去哪里执行
DiscardOldestPolicy
队列满了尝试去和最早创建的线程竞争
竞争失败不执行
DiscardPolicy
队列满了不执行多出的
自定义创建线程池
不能使用Executors去创建线程池
创建线程要使用ThreadPoolExecutor
Executors返回的线程池的弊端
FixedThreadPool 和SingleThreadPool
CachedThread和ScheduledThreadPool
JMM
什么是JMM
Java内存模型,不存在的东西,概念,约定。
JMM同步约定
线程解锁前,必须把共享变量立即刷回主存
线程加锁前,必须读取主存中的最新值到工作内存中
加锁核解锁必须是同一把锁
JMM八种指令
lock(锁定):作用于内存的变量,把一个变量标识为线程独占状态
unlock(解锁):作用域主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
read(读取):作用与工作内存的变量,它把一个变量的值从主内存中传输到线程的工作内存中,以便随后的load动作使用
load(载入):作用域工作内存的变量,它把read操作从主内存中的变量放入工作内存中
use(使用):作用域工作内存中的变量,它把工作内存的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个 指令
assign(赋值):作用域工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内的变量副本中
store(存储):作用域主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,一边后续的write使用
write(写入):作用域主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中
JMM八种指令使用规则
不允许read和load、store和write操作之一单独出现。几使用了read必须load,使用了store必须write
不允许线程丢弃它们最近的assign操作,即工作变量的数据改变了之后,必须告知主内存
不允许一个线程将没有assign的数据从工作内存同步回主内存
一个新的变量必须再主内存中诞生,不允许工作内存直接使用一个违背初始化的变量,就是对变量实施use,store操作之前必须经过assign和load操作
一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同数的unlock才能解锁
如果对一个变量进行lock操作,会情况所有工作内存中此变量的值,再执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
对一个变量进行unlock操作之前,必须把此变量同步回主内存
JMM工作流程
子主题
多线程
基础
创建线程的方法
继承Thread类
实现Runnable接口
实现Collable接口
使用线程池
线程的基本方法
getName():获取当前线程的名字
join():其他线程阻塞直至该线程执行完毕
sleep(int):使该线程睡眠毫秒数
yeild():让出cpu,让cpu重新调度
getPriority():返回该线程的优先级
getState():返回该线程的状态
stop():线程停止--已废弃!
线程状态
NEW :新生状态
RUNNABLE:运行状态
BLOCKED:被阻塞等待监视器锁定的线程处于此状态
WAITING:正在等待另一个线程执行特定动作的线程处于此状态
TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
TERMINATED:已退出的线程处于此状态
线程优先级
线程优先级范围:1-10;默认值:5
Thread . MIN_PRIORITY = 1
Thread . NORM_PRIORITY = 5
Thread . MAX_PRIORITY = 10
设置线程优先级:Thread.setPriority();
锁
synchronized
锁的对象
一个类
一个对象
一个Class
常量
会引发的问题
一个线程持有锁会导致其他所有需要此锁的线程挂起
在多线程竞争下,加锁,释放锁辉当值比较多的上下文切换和调度延时,引起性能问题
一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
Lock
synchronized与Lock区别
Synchronized 是内置的java关键字,Lock 是一个java类
Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
Synchronized 会自动释放锁,Lock 必须要手动解锁,如果不释放会死锁
Synchronized 线程1(获得锁,阻塞),线程2(等待,一直等),Lock锁就不一定会等待
Synchronized 可重入锁,不可以判断的,非公平,Lock 可重入锁,可以判断锁,可以设置公平非公平锁
Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码
Callable
Callable优点
1.可以有返回值
2.可以抛出异常
Callable使用
创建一个线程: new Thread();
创建一个FutureTask对象:new FutureTask(myTread);
启动线程:new Thread(futureTask).start();
四大函数式接口
Consumer
消费型接口
只有输入函数
没有输出函数
Function
函数型接口
有一个输入参数
有一个输出参数
Predicate
断定型接口
有一个只能为布尔类型的输出参数
Supplier
供给型接口
没有输入参数
ForkJoin
任务窃取
ForkJoinPool
ForkJoinTask
Votaile
保证可见性
不保证原子性
原子包装类
AtomicBoolean
AtomicInteger
AtomicLong
指令重排
你写的程序,计算机并不是按照你写的那样去执行的
处理器在进行指令重排的时候,考虑:数据之间的依赖性
CAS
Unasfe
Java无法操作内存
C++可以操作内存
Java可以通过Native调用C++操作内存
Java可以通过Unasfe类操作内存
自旋锁
比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么执行操作,如果不是就一直循环
CAS缺点
循环会耗时
一次性只能保证一个共享变量的原子性
存在ABA问题
AtomicStampedReference 注意,如果泛型是一个包装类,注意对象的引用问题,Integer 在-128~127
0 条评论
回复 删除
下一页