seamphore 和countDownlatch ReentLock都是基于AQS 用于线程间通信的工具。
CyclicBarrier:线程屏障. 和countDownLatch基本上差不多功能,不同地方就是CycliBarrier可以多次使用
seamphore:信号量,作用就是控制访问指定资源线程数目,底层依赖于AQS状态的status. 可以做限流 在微服务里面Hystix有两种限流方式 应该是基于线程池 另外一个就是基于信号量做的.
使用场景:在调用另外一个服务的时候可以加一个seamphore(3000) 也就是说最大支持过来的线程有3000个可以拿到信号量,拿不到信号量的线程全部都阻塞在外面。
Semaphore semaphore = new Semaphore(20);
//20相当于一开始参加两个票据
semaphore.acquire(2);//获取公共资源 从上面20给票据里面拿2个票据如果没有2个了会等这个方法支持中断
semaphore.release(); //将票据还回去
//也可以使用
if(seamphore.tryAcquire(500,....)) // 表示最多等500ms 如果还没有拿到票据注解降级
{
}else{
//降级的逻辑.........
}
Hsytil就是使用的这样的逻辑
CountDownLaunch:可以理解为计数器, 就是调用countDownLatch.await()会等待使用的线程都到达这个地方才会执行下面的逻辑 但是只能用一次
CountDownLatch countDownLatch = new CountDownLatch(10);
//new Threadxxxxxx逻辑1
//new Threadxxxxxx逻辑2
countDownLatch.await(); //这里就表示当所有的的线程都执行完逻辑1和逻辑2 才会去执行countDownLatch.await()方法后面的逻辑.
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(1);
/*new Thread(new SeeDoctorTask(countDownLatch)).start();
new Thread(new QueueTask(countDownLatch)).start();*/
for(int i=0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch.await(); //表示等到上面所有的线程都启动完成了才继续下面的逻辑 (相当于等所有的线程引擎执行下面的逻辑) 可以模拟线程的并行度
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
for(int j=0;j<1000;j++){
sub++;
}
}
}
});
}
Thread.sleep(3000);
//等待线程池中的2个任务执行完毕,否则一直等待,zk分布式锁
countDownLatch.countDown();
System.out.println("over,回家 cost:"+(System.currentTimeMillis()-now));
}
Atomic: 原子类的工具包.比如AtomicInreger AtomicBoolean等等......
使用就是参加1000个线程 堆count++ 用AtomicInteger可以直接保证原子行的操作,而不需要加synchronized. 底层是基于CAS的一种无锁的算法
CAS:比较与交换 底层就是基于unsafe类的api---> CASObject CASIntenge CASLong方法 最底层还是依赖硬件CMPXCHG去实现.
大概的逻辑: 就是先读取一份到数据到自己的工作内存里面去, 再去执行自己的业务逻辑去修改值,最后在拿自己工作内存里面的数据和主内存里面的数据进行比较(看看期间有没有线程堆主内存里面的数据进行修改) 如果保持一直就可以将修改后的值写回主内存里面,否则就丢弃.
要用CAS修改对象属性的值,就要做到该属性在对象内存空间里面的位置(也就是偏移量)
总结: Atomic底层是基于CAS实现的, CAS底层又是基于Unsafe类api实现的, Unsafe又是依赖于硬件实现.
ABA问题: 就是CAS原子比较与交换的bug.就是相当于比如说第一次出现数据为A 最后查询的数据也为A 但是中间有一个B的数据. A变成B B又变成A的过程没有看到.(假如有两个线程堆数据进行操作,T1查询数据为1 刚好T2将数据操作为2,此时T1的逻辑没有执行完成 T2快速又将数据改回1,此时T1再去查询数据还是1)
解决ABA问题:有一个版本号,数据变化一次版本号就+1 虽然最后数据一致,还会去比较版本号如果版本号不一致数据肯定被改过. AtomicStampeRefencce这个类可以做到
Unsafe魔法类: 堆外内存(虚拟机外面的空间)一般可以使用Unsafe这个类进行申请管理. 这个类里面有很多的native的方法. 在jdk1.7后提供了一些不安全的api可以绕过jvm内存管理直接可以操作内存系统资源.自主的去管理系统内存.. 就是可以理解Unsafe提供了一个后门直接可以操作系统资源.
有一个情况,假如对于文件上传,假如这个接口被很多的请求访问,就可以看到jvm使用率会非常的高, 就可以使用Unsafe申请堆外内存,业务堆外内存不属于GC管,使用用完一定要手动释放(否则会导致内存泄漏).