静态变量加锁失败问题

佛系睡收 2016-10-07 10:55:56
代码示例:
public class TestShareVariables {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new ShareDemo()).start();
}
//这里加个睡眠时间是为了保证让前面的线程类有足够时间运行好
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(ShareDemo.getCount());
}
}


class ShareDemo implements Runnable {

private static Integer count = 0;

public synchronized static int getCount() {
return count;
}

@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (ShareDemo.count) {
count++;
}
//这里加个睡眠时间是为了避免一个线程在获取到时间片时一次就运行完
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

最后得到的结果不一定都是50
为啥直接对静态变量加锁行不通,而将ShareDemo.count改为ShareDemo.class就没有问题了
...全文
404 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 4 楼 cqb18257344546 的回复:
因为你的静态变量值会改变,一改变锁就失效了 那如果是一个对象呢,改变了对象的一个属性,也会导致锁失效吗
不会
  • 打赏
  • 举报
回复
private static Integer count = new Integer(0);
count++;//每次执行这行代码的时候,count都会指向一个新的对象,
佛系睡收 2016-10-08
  • 打赏
  • 举报
回复
因为你的静态变量值会改变,一改变锁就失效了 那如果是一个对象呢,改变了对象的一个属性,也会导致锁失效吗
xiaovhao 2016-10-08
  • 打赏
  • 举报
回复
因为你的静态变量值会改变,一改变锁就失效了
佛系睡收 2016-10-08
  • 打赏
  • 举报
回复
虽然说了很多关于锁的机制,但是我的疑惑还是没解开
  • 打赏
  • 举报
回复
引用 7 楼 bichir 的回复:
主线程等待的时间不够久,再设长一点5000ms
仔细想了想也觉得可能是主线程输出的时候其他线程还没有执行完,如果所有子线程都执行完了,结果肯定是50
  • 打赏
  • 举报
回复
引用 2 楼 cqb18257344546 的回复:
虽然说了很多关于锁的机制,但是我的疑惑还是没解开
为什么我觉得一定是50呢?你出现过不是50的情况吗,能不能发一个截图,你的这个代码其实可以做到访问互斥的
佛系睡收 2016-10-08
  • 打赏
  • 举报
回复
引用 8 楼 qiaorh11 的回复:
synchronized (ShareDemo.count)锁的对象是变量count的实例。但是操作count++的结果会改变变量count的引用,所以同步块synchronized (ShareDemo.count)锁定的是不同的实例,也就是没有起到锁的作用。 synchronized (ShareDemo.class)锁的对象是ShareDemo.class对象,JVM只有1个,所以起到了同步的作用。
你这么一解释我就明白了,谢谢你了!
大眼鱼叔叔 2016-10-08
  • 打赏
  • 举报
回复
synchronized (ShareDemo.count)锁的对象是变量count的实例。但是操作count++的结果会改变变量count的引用,所以同步块synchronized (ShareDemo.count)锁定的是不同的实例,也就是没有起到锁的作用。 synchronized (ShareDemo.class)锁的对象是ShareDemo.class对象,JVM只有1个,所以起到了同步的作用。
bichir 2016-10-08
  • 打赏
  • 举报
回复
主线程等待的时间不够久,再设长一点5000ms
attilax 2016-10-07
  • 打赏
  • 举报
回复
Atitit.软件与编程语言中的锁机制原理attilax总结 1. 用途 (Db,业务数据加锁,并发操作加锁。 1 2. 锁得类型 排它锁 “互斥锁 共享锁 乐观锁与悲观锁 1 2.1. 自旋锁还是信号量 1 2.2. -自动释放还是手动释放 1 3. 实现方式,语言方式与库方式 1 4. Java的锁机制 Synchronized ReentrantLock AtomicInteger 2 5. C# 锁原理(Monitor类和lock关键词 ReaderWriterLock 2 6. Ref参考资料 3 1.用途 (Db,业务数据加锁,并发操作加锁。 2.锁得类型 排它锁 “互斥锁 共享锁 乐观锁与悲观锁 2.1.自旋锁还是信号量 2.2.-自动释放还是手动释放 3.实现方式,语言方式与库方式 Java.util.concurrent.lock 中的Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现。这就为Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。 Reen 4.Java的锁机制 Synchronized ReentrantLock AtomicInteger 是基于JVM来保证数据同步的,而Lock则是在硬件层面,依赖特殊的CPU指令实现数据同步的 实际JDK中也是通过一个32bit的整数位进行CAS操作来实现的。 需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而是用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内!!  Atomic* 开头的类基本原理都是一致的, 都是借助了底层硬件级别的 Lock 来实现原子操作的。 Cas原理 5.C# 锁原理(Monitor类和lock关键词 ReaderWriterLock C#提供了2种手工控制的锁 一:  Monitor类      这个算是实现锁机制的纯正类,在锁定的临界区中只允许让一个线程访问,其他线程排队等待。主要整理为2组方法。   1:Monitor.Enter和Monitor.Exit 微软很照护我们,给了我们语法糖Lock,对的 二:ReaderWriterLock类     先前也知道,Monitor实现的是在读写两种情况的临界区中只可以让一个线程访问,那么如果业务中存在”读取密集型“操作,就 好比数据库一样,读取的操作永远比写入的操作多。针对这种情况,我们使用Monitor的话很吃亏,不过没关系,ReadWriterLock 就很牛X,因为实现了”写入串行“,”读取并行“。 6.Ref参考资料 深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰的日志 - 网易博客.html 【Java线程】锁机制:synchronized、Lock、Condition - Alpha's 学习笔记 - 博客频道 - CSDN.NET.html Java常用锁机制简介 - hduhans - 博客园.html 5天不再惧怕多线程——第二天 锁机制 - 一线码农 - 博客园.html C# 多线程编程之锁的使用【互斥锁(lock)和读写锁(ReadWriteLock)】 - C#编程语言程序开发技术文章_C#编程 - 红黑联盟.html 锁机制与原子操作 _第四篇_ - 逆心 - 博客园.html 简单的JavaScript互斥锁.html 作者:: 绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 )  汉字名:艾提拉(艾龙),   EMAIL:1466519819@qq.com 转载请注明来源: http://blog.csdn.net/attilax atiend

67,514

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧