乐观锁 cas(要改的对象,期望的值,要给的值)无锁操作,其实是一个乐观锁…cas本身可以看成是一个锁
函数 | 效果 | 备注 |
---|---|---|
AtomicInteger a = new AtomicInteger(0); | int a = 0; | 创建对象a并且赋初值为0; |
a.incrementAndGet( ); | i++; | 对原值+1后返回; |
a.getAndIncrement( ); | ++i; | 对原值返回后+1; |
a.addAndGet(i); | a+=i; | 返回a+i; |
a.getAndAdd(i); | a+=i; | 返回原值之后给a+i; |
在线程很多的情况下:LongAdder(分段锁:在线程多的时候有优势) > Atomic > synchronized。
//可重入: synchronized void m1(){ for(int i = 1;i<10;i++){ try{ TimeUtil.SECONDS.sleep(1);// 睡一秒 }catch(InterruptedException e){ e.printStackTrace(); } sout(i); } } synchronized void m2(){sout("m2...");} public static void main(String[] args){ T01_ReentrantLock1 r1 = new T01_ReentrantLock1(); new Thread(r1::m1).start(); try{ TimeUtil.SECONDS.sleep(1);// 睡一秒 }catch(InterruptedException e){ e.printStackTrace(); } new Thread(r1::m2).start(); }
输出结果:0 1 23 4 5 6 7 8 9 m2…
代码修改:synchronized
//可重入: synchronized void m1(){ for(int i = 1;i<10;i++){ try{ TimeUtil.SECONDS.sleep(1);// 睡一秒 }catch(InterruptedException e){ e.printStackTrace(); } sout(i); if(i == 2){ new Thread(r1::m2).start(); } } } synchronized void m2(){sout("m2...");} public static void main(String[] args){ T01_ReentrantLock1 r1 = new T01_ReentrantLock1(); new Thread(r1::m1).start(); try{ TimeUtil.SECONDS.sleep(1);// 睡一秒 }catch(InterruptedException e){ e.printStackTrace(); } }
输出结果:0 1 2 m2 … 3 4 5 6 7 8 9
lock()
:替代 synchronized 的方法;Lock lock = new ReentrantLock();
特点:
lock.lock( );
lock.unlock( )
;try{ …… }catch( ){ …… }
优点:
可以使用tryLock()
尝试上锁;
当 synchronized
遇到锁之后只能等待,而tryLock()
可以自定义等待时间;
locked = lock.tryLock(SECONDS(时间长度),TimeUtil.SECONDS(时间格式:秒));
常用方法:
方法 | 参数 | 用法 |
---|---|---|
.lock( ); | null | 锁定 |
.unlock( ); | null | 释放 |
.tryLock(n,TimeUtil.SECONDS); | 时间长度 时间单位 |
等待参数 时间过程中:如果当前进程释放了,则锁定; 不释放则不锁定; |
.lockInterruptibly( ); | null; | 可以相应被打断的锁; |
.interrupt( ); | Null; | 打断这个锁; |
ReetrantLock lock = new ReentrantLock( true );
true
创建出来的就是公平锁;public class T05_ReentrantLock extends Thread(){
private stratic ReentrantLock lock = new ReentrantLock(true);
public void run(){
for(int i = 0;i<100;i++){
lock.lock();
try{
Sout(Thread.currentThread().getName()+"获得锁");
}finally{
lock.unlock();
}
}
}
}
CountDownLatch
CountDownLatch latch = CountDownLatch( threads.length );
//创建一个length长度的门栓
.await()
阻塞
原join()
当前线程结束自动往前走
.countDown()
原子性–
CyclicBarrier
循环栅栏工具
// 一个参数:不到20的时候,等待,到了20个,这20个发车,再来的继续等待
CyclicBarrier barrier = new CyclicBarrier(20);
// 两个参数:
CyclicBarrier barrier = new CyclicBarrier(20,run);
run(){ Sout("满员,发车!"); }
//lambdo 表达式
CyclicBarrier barrier = new CyclicBarrier(20,()->Sout("满员,发车!"));
按照不同的阶段对线程进行划分。
使用场景:
使用方法:
自定义一个类,继承 Phaser
类;
static class MarrigePhaser extends Phaser
重写onAdvance
方法;(栅栏被推倒的时候自动调用)
protected boolean onAdvance(int phase,int registeredParties)
方法:
phaser.arriveAndAwaitAdvance(); //执行结束,开始等待;
phaser.arriveAndDeregister(); //执行结束,不进入下一阶段;
程序中的读写锁(一种排他锁、共享锁)
概念
A
进程在读取ABCD
的时候,B
进程也来读取ABCD
,同时发现A
进程在读取,则读取成功;A
进程在读取ABCD
的时候,B
进程来修改ABCD
,同时发现A
进程在读取,若此时更改ABCD
的内容,则A
进程读取会出问题,所以修改失败;作用
static ReadWriteLoak readWriteLock = new ReentrantReadWriteLock();
//在 ReentrantReadWriteLock 中 分出一个 `readLock`一个`writeLock`
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
public static void read(Lock lock){
try{
lock.lock();
Thread.sleep(1000);
Sout("read over!");
// 模拟读取过程
}catch(InterruptedException e){
e.peintStackTrace();
}finally{
lock.unlock();
}
}
public static void write(Lock lock,int a){
try{
lock.lock();
Thread.sleep(1000);
Sout("write "+ a +"over!");
// 模拟读取过程
}catch(InterruptedException e){
e.peintStackTrace();
}finally{
lock.unlock();
}
}
public static void main(String[] args){
Runnable readR = ()->read(lock);
//Runnable readR = ()->read(readLock);
Runnable write = ()->write(lock,new Random().nextInt());
for (int i=0;i<18;i++)new Thread(readR ).start();
for (int i=0;i<2 ;i++)new Thread(writeR).start();
}
}
// 如果使用 ReentrantLock
的话,以上代码在执行读
的时候也需要等待一秒;
// 解决方法:将Main
方法中的读
锁换成Runnable readR = ()-> read(readLock);
Semaphore s = new Semaphore(x);
x是几则这个 < 线程池 > 就 允许几个线程 同时执行。
public static void main(String[] args){
Semaphore s = new Semaphore(1);
//括号中数字为x时,允许x个线程同时执行
// T1 Running
new Thread(()->{
try{
s.acquire();
// 进来一个进程 1 变成 0 ,别的线程不能执行
Sout("T1 Running");
Thread.sleep(200);
Sout("T1 Running");
}catch(InterruptedException e){
e.printStackTrace();
}finally{
s.release();
// 离开一个进程 0 变成 1 ,别的线程可以执行
}
});
// T2 Running
new Thread(()->{
try{
s.acquire();
// 进来一个进程 1 变成 0 ,别的线程不能执行
Sout("T2 Running");
Thread.sleep(200);
Sout("T2 Running");
}catch(InterruptedException e){
e.printStackTrace();
}finally{
s.release();
// 离开一个进程 0 变成 1 ,别的线程可以执行
}
});
}
如果x==1
则运行结果是T1 T1 T2 T2
,否则可能是T1 T2 T1 T2
使用场景:双人游戏中两人交换装备!执行一次就失效,可以循环等待下一次;
public static void main(String[] args){
// T1
new Thread(()->{
String s = "T1";
try{
s = sxchanger.exchange(s);
}cathc(InterruptedException e){
e.printStackTrace();
}
Sout(Thread.currentThread().getName()+""+s);
},"t1").start();
// T2
new Thread(()->{
String s = "T2";
try{
s = sxchanger.exchange(s);
}cathc(InterruptedException e){
e.printStackTrace();
}
Sout(Thread.currentThread().getName()+""+s);
},"t2").start();
}
线程中有两个变量,分别是
s
和s
(局部变量),两个线程同时执行,最后交换T1
与T2
的值;
只是某个类型的锁,将来补充概念。
synchronized
读写锁
可以大大提升效率lock
比synchronized
要灵活很多,但是需要自己加锁并释放锁,所以不是很方便