《JAVA并发编程实战》——线程安全,2024年最新闭关在家37天“吃透”这份345页PDF

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
img

正文

其实仔细一看,两个定义差不多,所谓的线程安全,都是对类而言的,如果多个线程同时访问这个类,这个类响应的结果都和预期的一样,那么说明这个线程是安全。

线程的安全性体现在三个方面:原子性、可见性、有序性

  • 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作。

  • 可见性:一个线程对主内存的修改可以及时的被其他线程看到

  • 有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序的存在,该观察结果一般杂乱无序。

原子性

JDK中atomic包

原子性是怎么实现的呢,在jdk中有一个Atomic包是保存可以确保线程的安全性

看下面的例子:

package com.mmall.concurrency.example.count;

import com.mmall.concurrency.annoations.ThreadSafe;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Semaphore;

import java.util.concurrent.atomic.AtomicInteger;

@ThreadSafe

public class CountExample2 {

// 请求总数

public static int clientTotal = 5000;

// 同时并发执行的线程数

public static int threadTotal = 200;

public static AtomicInteger count = new AtomicInteger(0);

public static void main(String[] args) throws Exception {

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore = new Semaphore(threadTotal);

final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal ; i++) {

executorService.execute(() -> {

try {

semaphore.acquire();

add();

semaphore.release();

} catch (Exception e) {

log.error(“exception”, e);

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println(count.get());

}

private static void add() {

count.incrementAndGet();

// count.getAndIncrement();

}

}

其实可以发现和文中最开始给出的例子想要做的事是一样的,只不过这里的count是AtomicInteger 类型的,也就是atomic包下的封装类。

public static AtomicInteger count = new AtomicInteger(0);

然后在count++ 操作时变成

count.incrementAndGet();

这个很有意思,这个才是确保这个类是线程安全的关键,可以看一下源码

public final int incrementAndGet() {

return unsafe.getAndAddInt(this, valueOffset, 1) + 1;

}

可以看到,调用了unsafe.getAndAddInt(this, valueOffset, 1) 方法,往下一层

public final int getAndAddInt(Object var1, long var2, int var4) {

int var5;

do {

var5 = this.getIntVolatile(var1, var2);

} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

return var5;

}

可以看到getAndAddInt方法的具体实现,var1为当前的对象,var2是当前count的值,var4是要加值,这里每次都是加1,所以var4的值为1.

var5的值是取主内存中当前count值,compareAndSwapInt()方法的关键是,如果从主内存中取出的当前count值var5与传入的当前count值var2不一致,那么就会重新取主内存count的值var5,只有当主内存的count值和当前count值相同时,才会将执行var5=varchat+var4操作。最后返回var5的值,这样就确保了每次在执行加一操作的时候得到的当前的count值都是最新的。

可以看到真正的核心就是compareAndSwapInt()方法啦,这就是是automic确保线程安全的CAS方法的具体实现。

另外再拓展一点:automic包下的AtomicLong类。看类名可以知道和AtomicInteger类一样,只是不同数据对应不同数据类型。但是在java8中新增一种类LongAdder.这个类和AtomicLong实现的功能是一样的,那为什么要在java8中新增一个LongAdder来替代AtomicLong呢。

刚刚上面讲了CAS的具体实现是通过循环一直判断,只有当值一样时候才会执行后续操作,低并发的时候还好,但是高并发的时候就会导致循环的次数增多,总而导致性能降低,使用LongAdder类,在低并发的时候和AtomicLong保持一直,但是在高并发的时候通过分散将压力分散到各个节点,总而提高高并发时的性能(具体的源码我也没有看,所以也是听被人说的这个,有兴趣的同学可以自己研究下)。但是LongAdder有个致命的缺点,就是虽然提高了性能,但是有的时候结果会出现偏差(通过离散模型统计的,在统计的时候,如果有并发更新,就可能会出现误差),导致如果需要结果是准确无误且唯一的时候最好使用AtomicLong。

在提一下atomic包下atomicStampReference类,这个类是解决CAS的ABA问题(是指一个线程操作某个值的时候,其他线程先修改了一次,然后又修改成原来的值。这样当前线程就会认为这个没有任何操作),但是实际上这个值是进行了2次操作的,值是把值改回去了,那怎么解决ABA问题呢,atomicStampReference类在线程操作某个值的时候,不仅会判断值,还会判断当前的版本号是否一致。一致才能进行下一步操作。线程在进行写或修改操作时会进行版本号加一。这样就能规避掉ABA问题了。

在看一下AtomicBoolean类。这个多线程调用类类让方法执行一次,也就是说比如5000个线程同时访问,但是只会有一个线程执行这个方法,其他的线程都不执行。

看一下代码:

package com.mmall.concurrency.example.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Semaphore;

import java.util.concurrent.atomic.AtomicBoolean;

@ThreadSafe

public class AtomicExample6 {

private static AtomicBoolean isHappened = new AtomicBoolean(false);

// 请求总数

public static int clientTotal = 5000;

// 同时并发执行的线程数

public static int threadTotal = 200;

public static void main(String[] args) throws Exception {

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore = new Semaphore(threadTotal);

final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal ; i++) {

executorService.execute(() -> {

try {

semaphore.acquire();

test();

semaphore.release();

} catch (Exception e) {

e.printStackTrace();

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println(isHappened.get());

}

private static void test() {

if (isHappened.compareAndSet(false, true)) {

System.out.println(“execute”);

}

}

}

结果:表明test()方法只执行了一次的。

execute

true

Synchronized

还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!

王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。

对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!

【完整版领取方式在文末!!】

93道网络安全面试题

内容实在太多,不一一截图了

黑客学习资源推荐

最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

1️⃣零基础入门
① 学习路线

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

image

② 路线对应学习视频

同时每个成长路线对应的板块都有配套的视频提供:

image-20231025112050764

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

.gif#pic_center)

② 路线对应学习视频

同时每个成长路线对应的板块都有配套的视频提供:

image-20231025112050764

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-EP0c7zY5-1713441872993)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值