线程的简单了解
- 进程、线程、纤程
- 创建线程的几种方式
- synchronized
- volatile
- AtomicX
- JUC 同步锁
- ReentrantLock
- CountDownLatch 倒数的门栓
- CyclicBarrier 复杂操作完成,再走后续逻辑
- Phaser 所有线程需要在屏障上等待才能进入下一步执行
- ReadWriteLock
- Semaphore
- Exchanger 线程间的通信
- LockSupport
- AbstractQueuedSynchronizer 队列
- (限流 Guava RateLimiter)
- 乐观锁与悲观锁
- 乐观锁与悲观锁的基本概念
- 何为乐观锁与悲观锁?
- 乐观锁与悲观锁的实现方式
进程、线程、纤程
进程:一个应用程序
线程:进程的最小执行单元
纤程:
创建线程的几种方式
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello MyThread!");
}
}
static class MyRun implements Runnable {
@Override
public void run() {
System.out.println("Hello MyRunable!");
}
}
static class MyCall implements Callable<String> {
@Override
public String call() {
System.out.println("MyCall Callable!");
return "success";
}
}
public static void main(String[] args) {
//继承thread类
new MyThread().start();
//实现runnable接口
new Thread(new MyRun()).start();
//lambda 表达式
new Thread(()->{
System.out.println("Hello Lambda!");
}).start();
//callable
Thread t=new Thread(new FutureTask<String>(new MyCall()));
t.start();
//线程池启动
ExecutorService executorService= ç.newCachedThreadPool();
executorService.execute(()->{
System.out.println(" my Callable");
});
executorService.shutdown();
}
synchronized
分别是无锁状态、偏向锁、轻量级锁和重量级锁
java中锁的四种状态
volatile
AtomicX
AtomicInteger
JUC 同步锁
ReentrantLock
Lock lock = new ReentrantLock();
CountDownLatch 倒数的门栓
CyclicBarrier 复杂操作完成,再走后续逻辑
参考:https://www.jianshu.com/p/128476015902
Phaser 所有线程需要在屏障上等待才能进入下一步执行
jdk 1.7 引入
onAdvance方法是protected方法,子类可以覆写,该方法是最后一个到达的线程执行的,如果返回true表示需要终止Phaser,否则继续下一轮的phase,因此可以借助该方法实现CyclicBarrier的回调函数功能,也可以控制Phaser的阶段数,
我们可以将Phaser的概念看成是一个个的阶段, 每个阶段都需要执行的线程任务,任务执行完毕后就进入下一阶段。这里和CyclicBarrier 和CountDownLatch的概念类似, 实际上也确实可以用Phaser代替CyclicBarrier和CountDownLatch。
Phaser也是通过计数器来控制, 在Phaser中叫parties, 我们在指定了parties之后, Phaser可以根据需要动态增加或减少parties的值。
Phaser 是一个障碍,在继续执行之前需要等待动态数量的线程。在 CountDownLatch 中,该数字不能动态配置,需要在我们创建实例时提供。
public int register() //向此移相器添加一个新的未到达方。
public int bulkRegister(int parties) // 将给定数量的新未到达方添加到此移相器。
public int arriveAndDeregister() // 到达此移相器并从其注销,而无需等待其他人到达
public int arrive() // 到达此移相器,无需等待其他人到达
public int arriveAndAwaitAdvance() // 到达这个移相器并等待其他人
public int awaitAdvance(int phase) // 等待此移相器的相位从给定的相位值前进,如果当前相位不等于给定的相位值或此移相器终止,则立即返回。
public int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit) // 等待此移相器的相位从给定的相位值或给定的超时时间过去,InterruptedException如果在等待时中断则抛出,或者如果当前相位不等于给定的相位值或此移相器终止,则立即返回
public final int getPhase() // 返回当前阶段号
public int getRegisteredParties() // 返回在此移相器上注册的参与方数量
public int getArrivedParties() // 返回已到达此移相器当前阶段的已注册方的数量
public int getUnarrivedParties() // 返回尚未到达此移相器当前阶段的已注册方的数量。
ReadWriteLock
StampedLock相较于普通读写锁,增加了一种乐观读。
可重入读写锁的基本使用,该锁只能在单服务实例中使用,不适合分布式多服务实例集群; ?
ReadWriteLock维护一对关联的locks,一个用于只读操作,一个用于写操作。read lock可以由多个阅读器同时进行,只要没有作者 write lock 是独家的。
写锁不存在、多次加读锁成功
写锁存在、加读锁失败、加写锁失败
读锁不存在、单次加写锁成功、多次加写锁只有第一个写锁能成功
读锁存在、加读锁成功、加写锁失败
Semaphore
Semaphore是一种计数信号量,用于控制对共享资源的访问。它维护了一个内部计数器,表示可用的许可数量。线程可以通过获取许可来访问资源,并在使用完资源后释放许可。如果许可数量为0,则获取许可的线程将被阻塞,直到有其他线程释放许可为止。
Semaphore是Java并发编程中一个强大的工具,用于控制对共享资源的访问和实现线程之间的同步。与其他并发控制机制相比,Semaphore具有灵活性和可扩展性。选择Semaphore还是其他机制取决于具体的需求和场景。在使用Semaphore时,需要注意正确地获取和释放许可,以避免死锁和资源争用等问题。
Exchanger 线程间的通信
两个线程之间交换数据
LockSupport
AbstractQueuedSynchronizer 队列
(限流 Guava RateLimiter)
乐观锁与悲观锁
乐观锁与悲观锁的基本概念
何为乐观锁与悲观锁?
乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题。
乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。
因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。
因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。
乐观锁与悲观锁的实现方式
悲观锁的实现方式是加锁,加锁既可以是对代码块加锁(如Java的synchronized关键字),也可以是对数据加锁(如MySQL中的排它锁)。