public static void writer() {
obj = new FinalExample();
}
public static void reader() {
FinalExample object = obj;
int a = object.i;
int b = object.j;
}
}
在前面有介绍,对于语句obj = new FinalExample();
其实对应有三个步骤:
- 分配内存空间
- 初始化对象
- 将内存空间的地址赋给对应的引用
CPU在执行时的指令重排,可能会导致第2个步骤在第3个步骤之后执行。对于以上代码就是返回的obj是一个还没有初始化好的对象。虽然构造函数执行了,但是其属性还未初始化完成,所以此时如果有一个线程B来调用其reader
方法,拿到的属性便是错误的数据。而final关键字会禁止CPU的这一行为,保证其初始化在构造函数返回之前执行。
synchronized
synchronized关键字可以作用于普通方法,静态方法, 代码块,运行时会对相应的位子进行加锁。
- 对于普通方法,锁是当前实例, 所以只有同一个实例调用该方法才会互斥
- 对于静态方法,锁是当前类的
Class
对象,类级别的锁。即使在不同的线程中调用不同实例对象,也会有互斥效果 - 对于同步代码块,锁是sychronized括号里配置的对象
普通方法/静态方法
我们定义一个类如下:
package com.fred.javalib.thread;
public class EmptyClass {
public synchronized void syncMethod() {
}
public synchronized static void syncStaticMethod() {
}
}
查看其字节码文件
可以发现, 被sychronized修饰的方法在被编译后,其方法的flags属性中会多一个
ACC_SYNCHRONIZED
标识。当虚拟机在访问有这个标识的方法时,会在相应的位置添加monitorenter
和monitorexit
指令
同步代码块
对于同步代码块, 是靠monitorenter
, monitorexit
指令来实现,我们用javap -verbose Singleton.class
来看一下上面用volatile
关键字实现的单例模式相关代码。
可以看到在上面的字节码中,有一个
monitorenter
和 2个monitorexit
。有monitorenter
是去拿锁, 有两个monitorexit
是因为其中一个是代码正常执行结束后释放锁,一个是在代码执行异常时释放锁。
happens-before规则
保证线和可见性的机制,前面一个操作的结果对后续操作是可见的。
1. 程序的顺序性原则
在一个线程中,按照程序顺序,前面的操作happens-before于后续的任意操作。
2. volatile变量规则
对于一个volatile变量的写操作, happens-before于后续对这个volatile变量的读操作。
3. 传递性
如果A happens-before B,且 B happens-before C,那么 A happens-before C。
4. 锁的规则
对于一个锁的解锁Happens-Before于后续对这个锁的加锁。
5. 线程start()规则
它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。
6. 线程join()规则
主线程A等待子线程B完成(主线程 A 通过调用子线程 B 的 join() 方法实现), 当子线程B完成后(主线程A中的join方法返回) 主线程能看到子线程的操作。所谓的“看到”,指的是对共享变量的操作。
操作系统层面提供的两种同步的方法
信号量与管程都是操作系统提供的两种同步的方法。多线程的并发导致资源竞争。同步就是协调多线程对共享数据的访问,任何时刻只能有一个线程访问。
信号量
信号量(semaphore)
是操作系统提供的协调共享资源访问的方法。软件同步是平等线程间的一种同步协商机制,信号量是由OS来进行管理的。信号量用来表示系统的一类资源,信号量的取值就是一类资源数。由Dijkstra在20世纪60年代提出, 是早期的操作系统里的主要同步机制,但现在很少用。 信号量是一种抽象的数据类型:
- 由一个整型变量(sem)和两个原子操作组成
- P()操作(荷兰语尝试减少)
- sem 减 1
- 如sem < 0, 进入等待,否则继续
- V()
- sem 加 1
- 如sem <=0, 唤醒一个等待进程
信号量是被保护的整型变量,初始化完成后,只能通过P和V操作修改,由操作系统保证,PV操作都是原子操作
- P可能阻塞,V不会阻塞(V操作只会释放资源, 不可能阻塞)
- 通常假定信号量是公平的,结程不会被无限期阻塞在P操作里,假定信号量等待按先进先出排队。
信号量实现临界区的资源访问
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BATJ 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《960全网最全Android开发笔记》
《379页Android开发面试宝典》
历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**