先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
-
规则1:线程对变量执行的前一个动作是load时才能执行use,反之只有后一个动作是use时才能执行load。线程对变量的read,load,use动作关联,必须连续一起出现。-----这保证了线程每次使用变量时都需要从主存拿到最新的值,保证了其他线程修改的变量本线程能看到。
-
规则2:线程对变量执行的前一个动作是assign时才能执行store,反之只有后一个动作是store时才能执行assign。线程对变量的assign,store,write动作关联,必须连续一起出现。-----这保证了线程每次修改变量后都会立即同步回主内存,保证了本线程修改的变量其他线程能看到。
-
规则3:有线程T,变量V、变量W。假设动作A是T对V的use或assign动作,P是根据规则2、3与A关联的read或write动作;动作B是T对W的use或assign动作,Q是根据规则2、3与B关联的read或write动作。如果A先与B,那么P先与Q。------这保证了volatile修饰的变量不会被指令重排序优化,代码的执行顺序与程序的顺序相同。
使用volatile关键字的特性
1.被volatile修饰的变量保证对所有线程可见。
由上文的规则1、2可知,volatile变量对所有线程是立即可见的,在各个线程中不存在一致性问题。那么,我们是否能得出结论:volatile变量在并发运算下是线程安全的呢?
这确实是一个非常常见的误解,写个简单的例子:
public class VolatileTest extends Thread{
static volatile int increase = 0;
static AtomicInteger aInteger=new AtomicInteger();//对照组
static void increaseFun() {
increase++;
aInteger.incrementAndGet();
}
public void run(){
int i=0;
while (i < 10000) {
increaseFun();
i++;
}
}
public static void main(String[] args) {
VolatileTest vt = new VolatileTest();
int THREAD_NUM = 10;
Thread[] threads = new Thread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++) {
threads[i] = new Thread(vt, “线程” + i);
threads[i].start();
}
//idea中会返回主线程和守护线程,如果用Eclipse的话改为1
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println("volatile的值: "+increase);
System.out.println("AtomicInteger的值: "+aInteger);
}
}
这个程序我们跑了10个线程同时对volatile修饰的变量进行10000的自增操作(AtomicInteger实现了原子性,作为对照组),如果volatile变量是并发安全的话,运行结果应该为100000,可是多次运行后,每次的结果均小于预期值。显然上文的说法是有问题的。
volatile修饰的变量并不保值原子性,所以在上述的例子中,用volatile来保证线程安全不靠谱。我们用Javap对这段代码进行反编译,为什么不靠谱简直一目了然:
getstatic指令把increase的值拿到了操作栈的顶部,此时由于volatile的规则,该值是正确的。
iconst_1和iadd指令在执行的时候increase的值很有可能已经被其他线程加大,此时栈顶的值过期。
putstatic指令接着把过期的值同步回主存,导致了最终结果较小。
volatile关键字只保证可见性,所以在以下情况中,需要使用锁来保证原子性:
-
运算结果依赖变量的当前值,并且有不止一个线程在修改变量的值。
-
变量需要与其他状态变量共同参与不变约束
那么volatile的这个特性的使用场景是什么呢?
-
模式1:状态标志
-
模式2:独立观察(independent observation)
-
模式3:“volatile bean” 模式
-
模式4:开销较低的“读-写锁”策略
具体场景:
2.禁止指令重排序优化。
由上文的规则3可知,volatile变量的第二个语义是禁止指令重排序。指令重排序是什么?简单点说就是
jvm会把代码中没有依赖赋值的地方打乱执行顺序,由于一些规则限定,我们在单线程内观察不到打乱的现象(线程内表现为串行的语义),但是在并发程序中,从别的线程看另一个线程,操作是无序的。
一个非常经典的指令重排序例子:
public class SingletonTest {
private volatile static SingletonTest instance = null;
private SingletonTest() { }
public static SingletonTest getInstance() {
if(instance == null) {
synchronized (SingletonTest.class){
if(instance == null) {
最后
看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题。
注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-Xa4coUhU-1713186495243)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!