synchronized 锁改变人生(类的实例对象的锁、Class实例对象的锁、代码块锁)
来源:互联网 发布:淘宝标题关键词优化 编辑:程序博客网 时间:2024/06/05 21:17
0、要从0开始,哈哈,因为工作的关系,并发用的不算多,synchronized用的不多,但是也必须要深入理解啊,咱们今天就搞搞synchronized,一探究竟。
1、先说说what is 线程安全?
答:用我自己话讲就是,如果一个实例方法是线程安全的,那就意味着同一时刻只有一个线程可以执行该实例方法。打个比方,假设实例方法比喻成公共卫生间,如果是线程安全的,那么这个卫生间就是那种独立卫生间,可以锁门,反之线程不安全,就是那种咱们原来学校的那种厕所(屁股对着屁股在大横勾里,high爆)!!
2、再说说线程不安全?
答:上面也提到一点,其实线程不安全的实例方法、静态方法等,都是可以被多个 线程 异步操作的,几乎几根线程同时会调用同一个方法、或者代码块!!!!!
3、上例子,未启用synchronized
类,Dog,有一个实例方法Barking,一个实例变量mBarkCount。
class Dog {private int mBarkCount = 0;public void Barking() {long threadId = Thread.currentThread().getId();System.err.println("线程 = " + threadId + " 正在调用……");mBarkCount++; //每调用一次,就加一次System.out.println("狗狗已经叫了:" + mBarkCount + "次");System.err.println("线程 = " + threadId + " 调用完成……");}}
public class MyWorkOne implements Runnable {@Overridepublic void run() {DriveMain.mDogInstance.Barking();}}
public class DriveMain {public static Dog mDogInstance;@BeforeClasspublic static void beforeGo(){mDogInstance = new Dog();}@Beforepublic void setUp(){}@Afterpublic void tearDown(){}@AfterClasspublic static void afterGo(){}@Testpublic void driveBark() {Thread[] threads = new Thread[5];Runnable runnable = new MyWorkOne();for(Thread thread: threads) {thread = new Thread(runnable);thread.start();}}}new 5 根Thread实例对象,同时调用同一个Dog实例对象的实例方法Barking
输出结果:
线程 = 12 正在调用……线程 = 16 正在调用……线程 = 12 调用完成……线程 = 16 调用完成……线程 = 15 正在调用……线程 = 15 调用完成……线程 = 13 正在调用……线程 = 14 正在调用……线程 = 13 调用完成……线程 = 14 调用完成……狗狗已经叫了:1次狗狗已经叫了:2次狗狗已经叫了:3次狗狗已经叫了:4次狗狗已经叫了:5次
因为没有使用synchronized修饰实例方法barking(),看的出来一个线程还没有调用完成,另外的线程就也开始调用该实例方法了。
4、我们为barking()实例方法加上关键字synchronized
public synchronized void Barking() {long threadId = Thread.currentThread().getId();System.err.println("线程 = " + threadId + " 正在调用……");mBarkCount++; //每调用一次,就加一次System.out.println("狗狗已经叫了:" + mBarkCount + "次");System.err.println("线程 = " + threadId + " 调用完成……");}
再看下输出结果:
线程 = 12 正在调用……狗狗已经叫了:1次狗狗已经叫了:2次狗狗已经叫了:3次狗狗已经叫了:4次线程 = 12 调用完成……线程 = 16 正在调用……线程 = 16 调用完成……线程 = 14 正在调用……线程 = 14 调用完成……线程 = 15 正在调用……线程 = 15 调用完成……线程 = 13 正在调用……线程 = 13 调用完成……狗狗已经叫了:5次是不是很清晰啊,线程 12 正在调用时,没有其它线程进来,等线程12调用结束,线程16又进来,线程16结束后,线程14才又进来…………………………
5、 因为调用的是实例方法, 所以线程之间获得就是类的实例对象锁,谁拿到锁,谁就去调用,用完了,再去释放锁,其它线程才有机会使用。
6、华丽丽的分割线…………………………………………………………………………………………………………………………………………………………
7、上面说完了实例方法,再让我们看看静态方法加上synchronized的快感
还是上面的例子, 老规矩,没加上锁的静态方法:
给Dog类加上该方法
public static void dogInHeat(){long threadId = Thread.currentThread().getId();System.err.println("线程: " + threadId + " 开始让狗狗发情了…………");System.err.println("线程: " + threadId + " 停止让狗狗发情了…………");}
public class MyWorkOne implements Runnable {@Overridepublic void run() {Dog.dogInHeat();}}
驱动类
@Testpublic void driveBark() {Thread[] threads = new Thread[5];Runnable runnable = new MyWorkOne();for(Thread thread: threads) {thread = new Thread(runnable);thread.start();}}输出结果:
线程: 13 开始让狗狗发情了…………线程: 16 开始让狗狗发情了…………线程: 14 开始让狗狗发情了…………线程: 14 停止让狗狗发情了…………线程: 15 开始让狗狗发情了…………线程: 15 停止让狗狗发情了…………线程: 12 开始让狗狗发情了…………线程: 16 停止让狗狗发情了…………线程: 13 停止让狗狗发情了…………线程: 12 停止让狗狗发情了…………看到了吧,没有加同步锁,线程13还没发情完毕,线程16就进来了
8、为静态方法加上同步锁
public synchronized static void dogInHeat(){long threadId = Thread.currentThread().getId();System.err.println("线程: " + threadId + " 开始让狗狗发情了…………");System.err.println("线程: " + threadId + " 停止让狗狗发情了…………");}
执行结果:
线程: 12 开始让狗狗发情了…………线程: 12 停止让狗狗发情了…………线程: 16 开始让狗狗发情了…………线程: 16 停止让狗狗发情了…………线程: 15 开始让狗狗发情了…………线程: 15 停止让狗狗发情了…………线程: 14 开始让狗狗发情了…………线程: 14 停止让狗狗发情了…………线程: 13 开始让狗狗发情了…………线程: 13 停止让狗狗发情了…………必须的整整齐齐的,一个线程工作完成后,另外一个线程才能开始调用
9、静态方法,因为是属于类的,所以每个线程拿到的是Class的实例对象的锁,哪根线程拿到该锁(每个class都是Class的实例对象),谁就能调用静态方法,调用完成后,释放锁,其它线程才有机会。。
10、华丽丽的分割线…………………………………………………………………………………………………………………………………………
11、让我们再来,除了为实例方法或者静态方法,整个方法体都加上同步锁。大牛们,还发明了 代码块锁(没错,我只同步一部分,其它随便异步),大写的牛逼………………
12、来把,代码块同步锁(实例对象的锁)
public void Barking() {long threadId = Thread.currentThread().getId();synchronized (this) {System.err.println("线程 = " + threadId + " 正在调用……");mBarkCount++; //每调用一次,就加一次System.out.println("狗狗已经叫了:" + mBarkCount + "次");System.err.println("线程 = " + threadId + " 调用完成……");}System.out.println("线程 = " + threadId + "未同步: 开始");System.out.println("线程 = " + threadId + "未同步: 结束");}
输出结果:
线程 = 12 正在调用……狗狗已经叫了:1次线程 = 12未同步: 开始线程 = 12未同步: 结束狗狗已经叫了:2次线程 = 15未同步: 开始线程 = 15未同步: 结束狗狗已经叫了:3次线程 = 12 调用完成……线程 = 15 正在调用……线程 = 15 调用完成……线程 = 16 正在调用……线程 = 16 调用完成……线程 = 14 正在调用……线程 = 16未同步: 开始线程 = 16未同步: 结束狗狗已经叫了:4次线程 = 14 调用完成……线程 = 13 正在调用……线程 = 14未同步: 开始线程 = 14未同步: 结束狗狗已经叫了:5次线程 = 13 调用完成……线程 = 13未同步: 开始线程 = 13未同步: 结束加了同步锁的代码块,依旧是谁持有锁,谁就可以调用, 上面的synchronized (this),this 必须代表的是当前类的实例对象,谁拿到它的锁,谁就可以调用此部分。(所有线程可要对应同一个实例对象,你别整多个实例对象,实例对象与实例对象之间可是独立的………………)
13、代码块锁(Class的实例对象的锁)
public void Barking() {long threadId = Thread.currentThread().getId();synchronized (Dog.class) {System.err.println("线程 = " + threadId + " 正在调用……");mBarkCount++; //每调用一次,就加一次System.out.println("狗狗已经叫了:" + mBarkCount + "次");System.err.println("线程 = " + threadId + " 调用完成……");}System.out.println("线程 = " + threadId + "未同步: 开始");System.out.println("线程 = " + threadId + "未同步: 结束");}这个 synchronized (Dog.class),可以用在实例方法里,可以用在静态方法里,毕竟是为了同步代码块,这里要强调的是,因为所有的实例对象,或者说一个类只有一个Class实例对象,所以这样的锁,我们也喜欢叫全局锁。
5个线程,创建5个对象,5个线程同时会调用各自实例对象的实例方法,此时一个线程拿到Class对象的锁,那这个同步代码块别的线程,你就不能执行(虽然不在同一个实例对象里)。全局锁的目的就是干这个的…………(我称为别人家的事情,老子也要干预…………zhenjiba草蛋)
14、对于 synchronized的延伸扩展,synchronized(Xx.class),虽然我们在不同的实例对象里被调用,但是哪根线程持有Class实例对象的锁,哪根线程才能调用我,哈哈,就是这么霸道!!!
public class MyWorkOne implements Runnable {@Overridepublic void run() {Dog dog = new Dog();dog.Barking();}}每个工作线程都new 一个 Dog对象,并调用它的实例方法 Barking(); (CAO,我竟然把实例方法名称,大写开头,我是sb%…………)
class Dog {public void Barking() {long threadId = Thread.currentThread().getId();synchronized (Dog.class) {System.err.println("线程 = " + threadId + " 正在调用……");System.err.println("线程 = " + threadId + " 调用完成……");}}}Dog有 同步代码块
public class DriveMain {@Testpublic void driveBark() {Thread[] threads = new Thread[5];Runnable runnable = new MyWorkOne();for(Thread thread : threads) {thread = new Thread(runnable);thread.start();}}}
new 5根 线程 , 开始 start()
线程 = 16 正在调用……线程 = 16 调用完成……线程 = 12 正在调用……线程 = 12 调用完成……线程 = 15 正在调用……线程 = 15 调用完成……线程 = 13 正在调用……线程 = 13 调用完成……线程 = 14 正在调用……线程 = 14 调用完成……
- synchronized 锁改变人生(类的实例对象的锁、Class实例对象的锁、代码块锁)
- JAVA Synchronized 关键字锁实例和锁CLASS对象的区别
- JAVA Synchronized 关键字锁实例和锁CLASS对象的区别
- 从头认识多线程-2.11 通过同步代码块证明synchronized标记的是对象锁
- java synchronized对象锁与类锁的区别、同步代码块与同步方法的区别
- java多线程-多线程同步代码块-银行存款实例-锁synchronized
- 线程锁的是对象(线程) synchronized 通过锁对象来锁代码
- synchronized详解-锁的是对象还是代码?
- 非静态方法的锁是实例对象本身(this),静态方法的锁是类对象本身(.class)
- Class对象使用实例,反射的基本原理
- synchronized关键字锁住的是对象还是代码块
- synchronized的锁对象的特点
- 2.6锁对象的改变
- synchronized取得的锁都是对象锁
- 关于synchronized,对象锁的理解
- 面向对象的基础知识:类Class,对象(Object),实例(Instance)
- Python面向对象的基础知识:类Class,对象(Object),实例(Instance)
- Class类实例化对象&取得类的结构
- C++STL 常用 函数 用法
- Jvm以及Jvm性能参数优化
- 写Detail的接口
- Android TextView系列--第二篇
- Gradle修改Maven仓库
- synchronized 锁改变人生(类的实例对象的锁、Class实例对象的锁、代码块锁)
- 第四周项目一(1)-求最大公约数
- 04-树4 是否同一棵二叉搜索树 (25分)
- java虚拟机自动内存管理机制
- 详解spl_autoload_register()函数
- 史上最全的ASP.NET MVC路由配置,以后RouteConfig再弄不懂神仙都难救你啦
- day10 内容提供者笔记
- How to play .rmvb files in Ubuntu
- android:SurfaceView绘制图形