java静态方法 lock_静态方法加锁,和非静态方法加锁区别

今天看了到有意思的题:在静态方法上加锁 和 非静态方法加锁 有什么区别,从而再次引出锁机制的一些理解。

先看方法:

// 这是一个很简单的类,里面共享静态变量 num,然后一个静态 和 非静态方法,都加上锁

// 我们假设有两个线程同时操作这两个方法,那么数据能互斥吗?

Java代码7b48fc8942749c12a49ad87eed3be763.png

public class Walk {

public static int num = 100;

public static Walk walk = new Walk();

// 静态

public synchronized static   int run(){

int i = 0;

while (i 

try {

num --;

i++;

System.out.println(Thread.currentThread().getName()+":"+num);

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

return num ;

}

// 非静态

public  synchronized int  walk(){

int i = 0;

while (i 

try {

num --;

i++;

System.out.println(Thread.currentThread().getName()+":"+num);

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

return num ;

}

}

// 先建立两个测试类,这里我们默认循环10次

public class T3 implements Runnable {

@Override

public void run() {

Walk walk = new Walk();

//Walk walk = Walk.walk;

walk.walk();

}

}

public class T1 implements Runnable{

@Override

public void run() {

Walk walk = new Walk();

//Walk walk = Walk.walk;

// 这里我依然用的new

walk.run();

}

}

Java代码7b48fc8942749c12a49ad87eed3be763.png

// 测试方法

public class Test {

public static void main(String[] args) {

Thread t1 = new  Thread(new T1());

Thread t3 = new  Thread(new T3());

ExecutorService es = Executors.newCachedThreadPool();

es.execute(t1);

es.execute(t3);

es.shutdown();

}

}

// 测试数据 我就不完全列出了

pool-1-thread-1:98

pool-1-thread-2:98

pool-1-thread-2:97

pool-1-thread-1:96

.....

可以看出两个线程没有互斥,这是为什么呢?

OK,我们将static 关键字去掉,代码我就不贴了,直接看结果。。

pool-1-thread-1:98

pool-1-thread-2:98

pool-1-thread-2:96

...

结果还是没有出现互斥现象,因此我们默认要先让一个线程执行10次的,假设我们这个是买票系统这是不允许的。为什么会出现这状况呢,方法都加上的锁的。

这里先引一下锁的理解,然后从后向前解释。

JAVA 的锁机制说明:每个对象都有一个锁,并且是唯一的。假设分配的一个对象空间,里面有多个方法,相当于空间里面有多个小房间,如果我们把所有的小房间都加锁,因为这个对象只有一把钥匙,因此同一时间只能有一个人打开一个小房间,然后用完了还回去,再由JVM 去分配下一个获得钥匙的人。

第二次实验,我们是对方法进行加锁了,但是没得到想要的结果,原因在于房间与钥匙。因为我们每个线程在调用方法的时候都是new 一个对象,那么就会出现两个空间,两把钥匙,而静态变量只有一个,相当于我们有两把钥匙,从不同的房间开门取共享的值,因此出错。

如果我们使用静态变量walk 呢?这代码放开,也就是我们统一使用一个对象去操作变量,那么结果..

使用 Walk.walk.walk();  和 Walk.run();

结果:还是没有互斥

pool-1-thread-1:99

pool-1-thread-2:98

pool-1-thread-1:97

...

如果我们把静态方法关键字 去掉: 就可以看见互斥现象了

pool-1-thread-1:99

pool-1-thread-1:98

pool-1-thread-1:96

结果发现还是会重复,因此我们可以得出,在静态方法上加锁,和普通方法上加锁,他们用的不是同一把所,不是同一把钥匙。从而得出 他们的对象锁是不同的,对象也是不同的。

这里再次引出一个概念:对象锁  和  类锁

对象锁:JVM 在创建对象的时候,默认会给每个对象一把唯一的对象锁,一把钥匙

类锁:每一个类都是一个对象,每个对象都拥有一个对象锁。

呵呵,概念感觉混淆了,其实都是锁,取两个名词,下面区分方便,效果是一样的,如果我们这样实现。

Java代码7b48fc8942749c12a49ad87eed3be763.png

// 静态,这里仅仅将方法所 变成了 类锁。

public  static int run(){

synchronized(Walk.class) {

int i = 0;

while (i 

try {

num --;

i++;

System.out.println(Thread.currentThread().getName()+":"+num);

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

return num ;

}

}

结果:

pool-1-thread-1:98

pool-1-thread-2:98

pool-1-thread-2:97

pool-1-thread-1:97

...

发现结果还是不是互斥的,说明在静态方法上加锁,和 实例方法加锁,对象锁 其实不一样的。如果我们改成:

synchronized(walk) {

//....略

}

结果:

pool-1-thread-2:99

pool-1-thread-2:98

pool-1-thread-2:97

这样就互斥了,因为T1 是通过静态变量walk 调用的,默认就是用的walk 对象这把锁,而静态方法 强制让他也使用 walk这把锁,就出现了互斥现象,因为钥匙只有一把。

如果我们两个方法都是静态方法呢?

..

小结:

1.对象锁钥匙只能有一把才能互斥,才能保证共享变量的唯一性

2.在静态方法上的锁,和 实例方法上的锁,默认不是同样的,如果同步需要制定两把锁一样。

3.关于同一个类的方法上的锁,来自于调用该方法的对象,如果调用该方法的对象是相同的,那么锁必然相同,否则就不相同。比如 new A().x() 和 new A().x(),对象不同,锁不同,如果A的单利的,就能互斥。

4.静态方法加锁,能和所有其他静态方法加锁的 进行互斥

5.静态方法加锁,和xx.class 锁效果一样,直接属于类的

6.(自己补的)照上边所说,如果同一个对象上的2个非static的方法上加锁,这2个方法虽然不是一个方法,但如果都加锁的话也会互斥,即同一个对象不同非static的方法加锁的话一个方法已经拿到锁了那另外一个线程用同一个对象调用另外一个线程时也会处于等待---总结就是如果锁非static的方法的话就如同锁对象,而且同一个对象只有一把锁。那锁不同的属性呢?

补:

分类:Java开发2013-12-19 13:49790人阅读

Java 中每一个对象都有一个锁,当线程访问synchronized 的方法和代码块的时候,会获得这个锁,也可以理解为为这个对象加锁,这个锁在同一时间有且只能被一个线程访问。如果一个线程访问对象锁的时候,锁正在被其他线程访问,那么这个线程就需要等待占用锁的那个线程释放对象锁,陷入阻塞状态。当执行完synchronized方法或者代码块的时候,线程就会释放对象锁。    当线程通过 synchronized 方法或者代码块获得对象锁后,其他线程无法访问对象的任何synchronized方法或者代码块,但是可以访问非synchronized方法或者代码块。    如果对静态方法添加synchronized 或者对静态变量的修改添加synchronized 块,那么这个时候获得的是类对象的锁。(class对象)    当线程休眠的时候,是不会释放对象锁。    可以把对象锁理解为资源,线程使用完这个资源后,会释放这个资源,以便其他线程来使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值