Java关键字synchronized的使用

private void synMethod() {

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

在上面的代码,我们可以看到我们开启了10个线程去执行count++操作,如果没有多线程的话,我们知道最后count的值一定是10000。

根据打印结果:

在这里插入图片描述

在这里插入图片描述

我们可以分析出上面十个线程都已经完成了1000次的循环,但是我们的打印并不如我们所料的是10000而是一个小于10000的值。

因为i++这个操作并不是原子性的(原子性就是操作不可中断),导致最后的结果并不是我们想要的,这就是我们所说的线程不安全。那我们如何实现线程安全呢,那就要用到我们今天的主角了,synchronized关键字。

现在我们来改造上面的代码,实现线程同步。

private synchronized void synMethod() {

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

改造上面的代码后,我在看我们的打印输出:在这里插入图片描述

就可以正确的得到我们想要的值了。

为什么synchronized能够实现同步?

我们知道我们写的java代码,最后都会编译class文件运行在虚拟机上(Android中编译成dex文件,dex文件是根据class文件演变而来的,去除了class文件中的冗余信息,效率更高,适合运行在移动设备上。)synchronized在经过编译后,会在同步块前后分别形成monitorenter和monitorexit这两个字节码指令。这个两个字节码呢,都需要一个reference类型参数来指明锁定和解锁的对象。

在执行monitor指令时,首先去尝试获取对象的锁,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数+1,在执行monitorexit指令时,会将计数器减一,当计数器为0时,锁就被释放了。

如果获取锁失败,那么当前线程就要阻塞,直到其他线程释放这个锁为止。

你以为到这就结束了?还没有。

下面我们再来看几段代码:

private void synMethod() {

synchronized (this){

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

}

private void synMethod() {

synchronized (Test.class){

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

}

private void synMethod() {

synchronized (object){

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

}

可以发现我们修改了synchronized的位置,但是无一例外,上面的几种写法,都能保证我们实现同步得到正确的值。

上面几种写法唯一不同的是,我们的synchronized关键字修饰的东西不一样。我们的synchronized可以修饰方法,代码块。

具体可以细分位以下几种场景:

1.synchronized 类的实例方法;

2.synchronized 类的静态方法;

3.synchronized 类的class对象;

4.synchronized this(当前类的实例);

5.synchronized obj(任意的实例对象);

第一种场景 synchronized 关键字锁住的是当前类的实例对象。

第二种场景 synchronized 关键字锁住的当前的类对象。

第三种场景 synchronized 关键字锁住的还是当前的类对象。

第四种场景 锁住的当前类的实例。

第五种场景 锁住的任意的实例对象。

注意如果锁主的是类对象的话,尽管new出多个实例,但他们仍然属于同一个类依然会被锁住。

以上五种场景我们主要分为三种情况去讨论:

1锁住当前类的实例,2锁住当前类的类对象,3锁住其他对象的实例

这三种情况有什么区别呢?

下面我们来看代码:

场景1:

Thread thread1 = new Thread(new Runnable() {

@Override

public void run() {

synMethod();

}

},“thread1”);

Thread thread2 = new Thread(new Runnable() {

@Override

public void run() {

synMethod2();

}

},“thread2”);

thread1.start();

thread2.start();

try {

thread1.join();

thread2.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

Log.v(“MyThreadText”,count+“”);

private void synMethod() {

synchronized (this){

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

}

private synchronized void synMethod2() {

for (int k = 0; k < 1000; k++) {

count++;

Log.v(“MyThreadText”,Thread.currentThread().getName()+" k:" +k + " count:"+count);

}

}

在这里插入图片描述

场景2:

Thread thread1 = new Thread(new Runnable() {

@Override

public void run() {

synMethod();

}

},“thread1”);

Thread thread2 = new Thread(new Runnable() {

@Override

public void run() {

synMethod2();

}

},“thread2”);

Thread thread3 = new Thread(new Runnable() {

@Override

public void run() {

synMethod3();

}

},“thread3”);

thread1.start();

thread2.start();

thread3.start();

try {

thread1.join();

thread2.join();

thread3.join();

} catch (InterruptedException e) {

总结

就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!

金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。

三面蚂蚁核心金融部,Java开发岗(缓存+一致性哈希+分布式)

总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!**

金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。

[外链图片转存中…(img-a3X5Vdxd-1719266517433)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值