多线程编程核心
2025-01-10 11:08:07 0 举报
AI智能生成
多线程编程核心
作者其他创作
大纲/内容
对象及变量的并发访问
Synchronized
对象锁
在方法(非Static)声明的地方加Synchronized的是当前类的对象
多个对象多个锁
类锁
在静态类上和方法上加锁是在类对应的Class类的单例对象加锁
A线程先持有Object的对象锁,B线程可以异步访问调用Object对象中的非同步方法
出现异常自动释放
重入
一个对象里面两个方法,调用一个带锁的方法时还可以调用第二个带锁的方法,内部互相调用
说明Synchronized使用的“对象监听器”是一个,使用的锁是一个
Synchronized(this)代码块锁的也是当前类对象
suspend和sleep调用完都不释放锁
a = "AA",b = "AA"
Synchronized(b)和Synchronized(a)是同一把锁,因为String常量池带来的原因,导致两个变量引用的都是一个,相当于同一个object
Synchronized(b)和Synchronized(a)是同一把锁,因为String常量池带来的原因,导致两个变量引用的都是一个,相当于同一个object
会把私有内存中的数据同共有内存中的数据同步,使私有内存的数据和共有内存的数据一致
实例变量是非线程安全的,局部变量是线程安全的
volatile
可见性
使用synchronized就没没必要使用volatile来声明私有变量了
实例化的对象不可以
每次是从共有的内存中读取对象,不是私有内存
原子性
禁止代码重排
volatile int i++的操作是非原子性
从内存中取值i
计算i
将i写入内存
锁的使用
ReentranLock
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock
lock.lock();
lock.unlock
具有互斥排他性
await
使用当前线程在接收通知或者别中断之前,一直处于等待状态和wait方法作用是一样的
也会释放锁
signal
公平锁
非公平锁(默认)
trylock
如果在规定时间内持有锁,返回true,拿到的true没拿到的false
嗅探拿锁,如果当前发现锁被其他的线程持有就返回Fals
ReentrantReadWriteLock读写锁
共享锁
lock.readLock().lock();
lock.readLock().unlock();
排他锁
lock.writeLock().lock();
lock.writeLock().unlock();
读写互斥,读读共享,写写互斥
单例与多线程
饿汉
饿汉就是类加载器加载完 我就要吃一口 我就要有这个实例 以后用的都是被咬过的
懒汉
懒汉相当于 别烦我 用的话我就起来一次 给你建好 然后每回用的话 做逻辑判断 是不是空 是空我再起来创建
饿汉模式和静态内部类实现单例模式的优点是写法简单,缺点是不适合复杂对象的创建。对于涉及复杂对象创建的单例模式,比较优雅的实现方式是懒汉模式,但是懒汉模式是非线程安全的,下面就讲一下懒汉模式的升级版——双重构校验锁模式(双重构校验锁是线程安全的)。
为什么是双重校验 ?
第二次校验是为了解决问题①,即避免多个线程重复创建对象。
第一次校验是为了提高效率,避免 INSTANCE 不为null时仍然去竞争锁。
public class Lock2Singleton {
private volatile static Lock2Singleton INSTANCE; // 加 volatile
private Lock2Singleton() {}
public static Lock2Singleton getSingleton() {
if (INSTANCE == null) { // 双重校验:第一次校验
synchronized(Lock2Singleton.class) { // 加 synchronized
if (INSTANCE == null) { // 双重校验:第二次校验
INSTANCE = new Lock2Singleton();
}
}
}
return INSTANCE;
}
为什么加 volatile ?
加 volatile 是为了禁止指令重排序,也就是为了解决问题②,即避免某个线程获取到其他线程没有初始化完全的对象。
static静态代码块
将new对象放在静态代码块中,代码在使用类的时候就已经执行,不会存在重复创建对象
线程池
new TreadPoolExecutor(corePoolSize,MaximumPollSize,KeepAliveTime,TimeUnit.SECONDS,new LinkedLockingQueue)
使用SynchronousQueue
使用LinkedBlockingQueue
KeepAliveTime
当线程数量大于核心线程数,没超过等待时间是不会被从LinkedLockingQueue),如果是超过此时间范围的,删除空闲的线程,
范围是max~core 也就是core之外的
范围是max~core 也就是core之外的
Java多线程技能
实现Runnable接口 重写Run方法
继承Tread 类(Runnable实现类) 重写Run方法
线程启动使用 Thread.start() 如果调用的是Tread.run就不是异步执行了
判断线程是不是停止状态
interrupted
currentThread()是否已经中断
判断完之后会把当前状态变为非中断
第一次调用完清除登陆状态
isInterrupted
只做判断
只要interrupt和sleep碰到一块就会出现异常
方法
stop暴力停止
suspend暂停
独占
resume恢复线程执行
独占
yield()放弃当前Cpu资源
线程优先级有继承性
比如A线程启动B线程AB优先级一样
CPU会优先执行优先级比较高的线程
setPriority
多线程中线程之前切换是随机的
守护线程
随主线程的毁灭而毁灭,相当于JVM中一直有线程做着辅助工作
并发
一个CPU同时处理多个任务
并行
多个CPU同时处理多个任务
线程之间的通信
wait/notify机制
wait的作用是使线程暂停运行,不是在notify执行之后立即释放锁,而是等当线程执行完毕后再唤醒
必须执行完notify方法所在的同步代码块执行完
必须执行完notify方法所在的同步代码块执行完
notify通知暂停的线程继续运行,仅通知一个,只唤醒等待的同一把锁的wait
notifyAll()会按照wait的倒序以此唤醒全部线程
wait必须要有synchorized,是object的方法
join
在内部使用wait 进行等待 会释放锁
ThreadLocal
线程的Map存放自己的线程,向每个线程存储自己的私有数据,线程安全
定时器
Timer
cancel清除自身外所有任务
多个线程在不同的TimerTask切换的算法的顺序每次将最后一个任务放在队列头,:abc、cab、bca
Timer Task、
cancel清除自身
schedule(TimeTasjk task, Date firstTime, long period):该方法作用是在指定日期后按照指定时间间隔,无限循环执行任务
Long noeTime = System.currentTimeMillis()
Long sheduletime = nowTIme+10
Mytask extends TimerTask
Nytask task = new MyTask()
Timer time = New Timer()
time.shedule(task,new Date(sheduleTimer))
Long sheduletime = nowTIme+10
Mytask extends TimerTask
Nytask task = new MyTask()
Timer time = New Timer()
time.shedule(task,new Date(sheduleTimer))
并发集合框架
非阻塞队列
concurrentHashMap
是在HashMap基础上多个多并发
支持多线程并发环境下的put与remove,创建方式与HashMap相同
不支持排序
ConcurrentSkipListMap
支持多线程并发排序
ConcurrentSkipListSet
支持排序且不允许重复
ConcurrentLinkedQueue
并发环境下的队列
ConcurrentLinkedDeque
支持对队列头和列尾的操作
CopyOnWriteArraySet与CopyOnWriteArrayList
分别解决HashSet与ArrayList在都线程情况下的线程安全问题
没有值就会报错
阻塞队列
当队列里面没有值一直处于等待,直到有值才会继续
当队列是满的,没有剩余空间等待
LinkedBlockingQueue
有一个可选的容量限制,可以在创建时指定。
LinkedBlockingQueue的插入和移除操作是分别独立的,可以同时进行多个插入和移除操作。
公平性策略,即按照线程的到达顺序来进行插入和移除操作的公平竞争
插入操作可以选择阻塞或者非阻塞,而移除操作始终是阻塞的。
SynchronousQueue
同步队列,每个插入操作都必须等待另一个线程对应的移除操作完成,否则会被阻塞
没有容量限制,每个插入操作必须等待一个对应的移除操作
SynchronousQueue的插入和移除操作是一对一的,也就是说,一个线程在插入元素时会阻塞,直到另一个线程从队列中移除这个元素
没有公平性策略,插入和移除操作是非公平的。
插入操作会阻塞,直到有另一个线程进行相应的移除操作
0 条评论
下一页