Open realpdai opened 3 years ago
问题章节:https://pdai.tech/md/java/thread/java-thread-x-key-volatile.html 实现可见性 public void change(){ a = 3; b = a; } 文章结论说如果将a和b都改成volatile类型的变量再执行,则再也不会出现b=2;a=3和b=3;a=1的结果了。 实测还是会的,因为volatile只能保证单次原子性,b=a:实际是两次操作,读取a的值 - 将a赋值给b
作者您好,
在关键字: synchronized详解 文中,JVM 中锁的优化中对于偏向锁的介绍 以后该线程在进入和推出同步块时不需要进行CAS操作来加锁和解锁
推出应该修改为退出
pdai 你好,在文章 https://pdai.tech/md/java/thread/java-thread-x-key-volatile.html#%E5%AE%9E%E7%8E%B0%E5%8F%AF%E8%A7%81%E6%80%A7 中,
“实现可见性”时,举例代码如下:
public class VolatileTest {
int a = 1;
int b = 2;
public void change(){
a = 3;
b = a;
}
public void print(){
System.out.println("b="+b+";a="+a);
}
public static void main(String[] args) {
while (true){
final VolatileTest test = new VolatileTest();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.change();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.print();
}
}).start();
}
}
}
文中说"如果将a和b都改成volatile类型的变量再执行,则再也不会出现b=2;a=3和b=3;a=1的结果了。"
我认为不太合适。因为volatile
只能保证单次的读/写操作具有原子性。就算二者都加上 volatile
,有可能会有线程一执行完a=3,线程二输出“b=2;a=3”,然后线程一才执行b=a。
如果将change()
方法改成下面,很容易得到输出b=2,a=3。
public void change() {
a = 3;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
b = a;
}
运行如下:
我觉得下面这个例子比较清晰(摘自 https://blog.csdn.net/zhujiangtaotaise/article/details/122493682 ):
public class TestVolatile { static boolean stop = false; public static void main(String[] args) throws InterruptedException { new Thread("线程1") { @Override public void run() { while (!stop) { } System.out.println("线程停下来了"); } }.start(); TimeUnit.MILLISECONDS.sleep(200); stop = true; System.out.println("需要停下来 >>> " + stop); } }
可以看到 主线程休眠200毫秒之后,设置 stop = ture,但是线程1根本没停下来,这就是可见性问题。 可以通过在 变量 stop 前面加上 volatile 关键字解决,大家可以自己验证。
感谢!
https://www.pdai.tech/md/java/thread/java-thread-x-key-final.html
示例代码处,FinalReferenceEscapeDemo属性、writer方法、reader方法应该都要加static,普通方法都要构造方法初始化完成后才能去调用执行,不应该存在溢出情况
https://www.pdai.tech/md/java/jvm/java-jvm-struct.html#_5-5-%E6%96%B9%E6%B3%95%E5%8C%BA%E5%9C%A8-jdk6%E3%80%817%E3%80%818%E4%B8%AD%E7%9A%84%E6%BC%94%E8%BF%9B%E7%BB%86%E8%8A%82 在方法区中 JDK 各版本的演进细节中有提到。JDK 1.7 中,类静态变量已经被移动到堆中了。
https://www.pdai.tech/md/java/jvm/java-jvm-struct.html#_5-3-%E6%96%B9%E6%B3%95%E5%8C%BA%E5%86%85%E9%83%A8%E7%BB%93%E6%9E%84 那这里介绍方法区的内部结构时,还提到包括了类的静态变量。这两部分冲突吗?
https://www.pdai.tech/md/java/jvm/java-jvm-gc.html#_2-%E5%8F%AF%E8%BE%BE%E6%80%A7%E5%88%86%E6%9E%90%E7%AE%97%E6%B3%95 另外还有在 GC Roots 的介绍中,GC Roots:也包括 方法区中类静态属性引用的对象。 这里是不是也和类静态属性存放在堆中有冲突呢
作者您好,数据库=》NoSQL数据库=》MongoDB详解 左侧导航未能正确显示文章 MongoDB 替换方案之PostgreSQL(https://pdai.tech/md/db/nosql-mongo/postgresql-replace.html) 的名称,跳转链接也不正确。当前显示为 nosql-mongo/postgresql-replace.html, 跳转链接为 https://www.pdai.tech/md/db/nosql-redis/nosql-mongo/postgresql-replace.html
pdai大大,您好,你的网站对我帮助很大,非常感谢;同时我想问下spring系列可否增加事务相关的知识解读呢
作者你好: 文章链接:https://www.pdai.tech/md/java/thread/java-thread-x-key-synchronized.html#%E9%94%81%E7%B2%97%E5%8C%96
如果更新成功了,那么这个线程就 有用 了该对象的锁,并且对象Mark Word的锁标志位更新为(Mark Word中最后的2bit)00,即表示此对象处于轻量级锁定状态
有用 -> 拥有?
直接膨胀 位 重量级锁,没有获得锁的线程会被阻塞。此时,锁的标志位为10.Mark Word中存储的 时 指向重量级锁的指针。
位 -> 为?时 -> 指针?
如线程 成 始终得不到锁竞争的线程,使用自旋会消耗CPU性能
成多余?
Synchronized 只有锁 只与一个条件(是否获取锁)相关联,不灵活,后来Condition与Lock的结合解决了这个问题。
这个“只有锁”是?
最后暗色模式下,看不见写评论这个文本域的字,样式问题 我用的谷歌浏览器(版本 108.0.5359.99(正式版本) (64 位))
文章:Map - LinkedHashSet&Map源码解析 链接:https://pdai.tech/md/java/collection/java-map-LinkedHashMap&LinkedHashSet.html
这里有关 LinkedHashMap 的内容是 JDK7 的实现,和 JDK8 的实现差异比较大,可以标明一下。如果能直接换成 JDK8 相关的资料就更好了。
https://www.pdai.tech/md/java/jvm/java-jvm-struct.html JVM 基础 - JVM 内存结构 这篇文章的图片全部不可见了, 新浪图床那边403了
pdai大大好: https://www.pdai.tech/md/java/thread/java-thread-x-lock-all.html 错误点:首先ReentrantLock和NonReentrantLock都继承父类AQS 应该改为:FairSync和NonFairSync继承于Sync,Sync继承于AQS,而ReentrantLock中持有/组合了Sync。
https://www.pdai.tech/md/java/thread/java-thread-x-key-synchronized.html 错误点:static SynchronizedObjectLock instence = new SynchronizedObjectLock();
instence应为instance,好多地方都拼写错误了😶
https://www.pdai.tech/md/java/thread/java-thread-x-juc-AtomicInteger.html 错误点:操作线程Thread[主操作线程,5,main],初始值 a = 2 更正为:操作线程Thread[主操作线程,5,main],初始值 a = 1
JUC锁:LockSupport详解 这个页面打不开
@xiangboit
https://www.pdai.tech/md/java/thread/java-thread-x-juc-AtomicInteger.html AtomicStampedReference解决CAS的ABA问题 输出举例是错误的正确的输出 操作线程Thread[主操作线程,5,main],初始值 a = 1 操作线程Thread[干扰线程,5,main],【increment】 ,值 = 2 操作线程Thread[干扰线程,5,main],【decrement】 ,值 = 1 操作线程Thread[主操作线程,5,main],CAS操作结果: false
已经更新原有代码可能带来的执行差异,感谢指出。
@zhangtuodd
问题章节:https://pdai.tech/md/java/thread/java-thread-x-key-volatile.html 实现可见性 public void change(){ a = 3; b = a; } 文章结论说如果将a和b都改成volatile类型的变量再执行,则再也不会出现b=2;a=3和b=3;a=1的结果了。 实测还是会的,因为volatile只能保证单次原子性,b=a:实际是两次操作,读取a的值 - 将a赋值给b
感谢指出,已经更换例子,原例子不合适。
@chunyizanchi
作者您好, 在关键字: synchronized详解 文中,JVM 中锁的优化中对于偏向锁的介绍
以后该线程在进入和推出同步块时不需要进行CAS操作来加锁和解锁
推出应该修改为退出
感谢指出,已经更正。
@Scrates1
问题及内容
pdai 你好,在文章 https://pdai.tech/md/java/thread/java-thread-x-key-volatile.html#%E5%AE%9E%E7%8E%B0%E5%8F%AF%E8%A7%81%E6%80%A7 中,
“实现可见性”时,举例代码如下:
public class VolatileTest { int a = 1; int b = 2; public void change(){ a = 3; b = a; } public void print(){ System.out.println("b="+b+";a="+a); } public static void main(String[] args) { while (true){ final VolatileTest test = new VolatileTest(); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } test.change(); } }).start(); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } test.print(); } }).start(); } } }
文中说"如果将a和b都改成volatile类型的变量再执行,则再也不会出现b=2;a=3和b=3;a=1的结果了。"
我的观点
我认为不太合适。因为
volatile
只能保证单次的读/写操作具有原子性。就算二者都加上volatile
,有可能会有线程一执行完a=3,线程二输出“b=2;a=3”,然后线程一才执行b=a。如果将
change()
方法改成下面,很容易得到输出b=2,a=3。public void change() { a = 3; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } b = a; }
运行如下:
建议
我觉得下面这个例子比较清晰(摘自 https://blog.csdn.net/zhujiangtaotaise/article/details/122493682 ):
public class TestVolatile { static boolean stop = false; public static void main(String[] args) throws InterruptedException { new Thread("线程1") { @Override public void run() { while (!stop) { } System.out.println("线程停下来了"); } }.start(); TimeUnit.MILLISECONDS.sleep(200); stop = true; System.out.println("需要停下来 >>> " + stop); } }
可以看到 主线程休眠200毫秒之后,设置 stop = ture,但是线程1根本没停下来,这就是可见性问题。 可以通过在 变量 stop 前面加上 volatile 关键字解决,大家可以自己验证。
感谢!
非常感谢详细的指出问题,已经更新例子,thx.
@ChlZhYa
https://www.pdai.tech/md/java/jvm/java-jvm-struct.html#_5-5-%E6%96%B9%E6%B3%95%E5%8C%BA%E5%9C%A8-jdk6%E3%80%817%E3%80%818%E4%B8%AD%E7%9A%84%E6%BC%94%E8%BF%9B%E7%BB%86%E8%8A%82 在方法区中 JDK 各版本的演进细节中有提到。JDK 1.7 中,类静态变量已经被移动到堆中了。
https://www.pdai.tech/md/java/jvm/java-jvm-struct.html#_5-3-%E6%96%B9%E6%B3%95%E5%8C%BA%E5%86%85%E9%83%A8%E7%BB%93%E6%9E%84 那这里介绍方法区的内部结构时,还提到包括了类的静态变量。这两部分冲突吗?
https://www.pdai.tech/md/java/jvm/java-jvm-gc.html#_2-%E5%8F%AF%E8%BE%BE%E6%80%A7%E5%88%86%E6%9E%90%E7%AE%97%E6%B3%95 另外还有在 GC Roots 的介绍中,GC Roots:也包括 方法区中类静态属性引用的对象。 这里是不是也和类静态属性存放在堆中有冲突呢
@realpdai: HotSpot中字符串常量池保存哪里?永久代?方法区还是堆区?
JDK版本 | 是否有永久代,字符串常量池放在哪里? | 方法区逻辑上规范,由哪些实际的部分实现的? |
---|---|---|
jdk1.6及之前 | 有永久代,运行时常量池(包括字符串常量池),静态变量存放在永久代上 | 这个时期方法区在HotSpot中是由永久代来实现的,以至于这个时期说方法区就是指永久代 |
jdk1.7 | 有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中; | 这个时期方法区在HotSpot中由永久代(类型信息、字段、方法、常量)和堆(字符串常量池、静态变量)共同实现 |
jdk1.8及之后 | 取消永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆中 | 这个时期方法区在HotSpot中由本地内存的元空间(类型信息、字段、方法、常量)和堆(字符串常量池、静态变量)共同实现 |
@qiyu666
作者你好: 文章链接:https://www.pdai.tech/md/java/thread/java-thread-x-key-synchronized.html#%E9%94%81%E7%B2%97%E5%8C%96
如果更新成功了,那么这个线程就 有用 了该对象的锁,并且对象Mark Word的锁标志位更新为(Mark Word中最后的2bit)00,即表示此对象处于轻量级锁定状态
有用 -> 拥有?
直接膨胀 位 重量级锁,没有获得锁的线程会被阻塞。此时,锁的标志位为10.Mark Word中存储的 时 指向重量级锁的指针。
位 -> 为?时 -> 指针?
如线程 成 始终得不到锁竞争的线程,使用自旋会消耗CPU性能
成多余?
Synchronized 只有锁 只与一个条件(是否获取锁)相关联,不灵活,后来Condition与Lock的结合解决了这个问题。
这个“只有锁”是?
最后暗色模式下,看不见写评论这个文本域的字,样式问题 我用的谷歌浏览器(版本 108.0.5359.99(正式版本) (64 位))
已经更新,感谢指出。
@MikeKctrina
pdai大大,您好,你的网站对我帮助很大,非常感谢;同时我想问下spring系列可否增加事务相关的知识解读呢
后续会安排,感谢。
@micro-coding
作者您好,数据库=》NoSQL数据库=》MongoDB详解 左侧导航未能正确显示文章 MongoDB 替换方案之PostgreSQL(https://pdai.tech/md/db/nosql-mongo/postgresql-replace.html) 的名称,跳转链接也不正确。当前显示为 nosql-mongo/postgresql-replace.html, 跳转链接为 https://www.pdai.tech/md/db/nosql-redis/nosql-mongo/postgresql-replace.html
感谢指出,已经更新。
@weihanhan
文章:Map - LinkedHashSet&Map源码解析 链接:https://pdai.tech/md/java/collection/java-map-LinkedHashMap&LinkedHashSet.html
这里有关 LinkedHashMap 的内容是 JDK7 的实现,和 JDK8 的实现差异比较大,可以标明一下。如果能直接换成 JDK8 相关的资料就更好了。
感谢指出,已经增加标题。
@chn-yang
https://www.pdai.tech/md/java/jvm/java-jvm-struct.html JVM 基础 - JVM 内存结构 这篇文章的图片全部不可见了, 新浪图床那边403了
感谢指出,已经更新。
@dby321
pdai大大好: https://www.pdai.tech/md/java/thread/java-thread-x-lock-all.html 错误点:首先ReentrantLock和NonReentrantLock都继承父类AQS 应该改为:FairSync和NonFairSync继承于Sync,Sync继承于AQS,而ReentrantLock中持有/组合了Sync。
你这么说更详细,原话其实也没啥问题。
@dby321
https://www.pdai.tech/md/java/thread/java-thread-x-key-synchronized.html 错误点:static SynchronizedObjectLock instence = new SynchronizedObjectLock();
instence应为instance,好多地方都拼写错误了😶
已经更正,感谢指出。
@dby321
https://www.pdai.tech/md/java/thread/java-thread-x-juc-AtomicInteger.html 错误点:操作线程Thread[主操作线程,5,main],初始值 a = 2 更正为:操作线程Thread[主操作线程,5,main],初始值 a = 1
感谢指出,已经更新相关代码带来的差异及输出。
@dby321
JUC锁:LockSupport详解 这个页面打不开
已经更新,感谢。
作者你好,在这归并排序这篇文章https://pdai.tech/md/algorithm/alg-sort-x-merge.html#%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F%E5%AE%9E%E7%8E%B0中。 归并排序实现-->从上往下的归并排序 图解上的数值是不是写错了,应该是{80,30,60,40,20,10,50,70}吧
Mongo入门 - MongoDB基础概念 为什么使用NoSQL?
为了解决此问题,当然可以通过升级现有硬件来“横向扩展”我们的系统。但这个成本很高。 应该是纵向扩展
https://pdai.tech/md/framework/orm-mybatis/mybatis-y-datasource.html “ 首先让我们来看一下创建一个java.sql.Connection对象的资源消耗。我们通过连接Oracle数据库,创建创建Connection对象,来看创建一个Connection对象、执行SQL语句各消耗多长时间。代码如下: ”
多了一个创建
java集合-类关系图中,LinkedList没有直接impliment Deque接口,图中却实现了(java8版本)
作者好, 全栈知识点汇总(上): 5.2 内存结构 jvm-framework,jvm-stack-frame,JDK7 三张图片丢失了
作者你好,https://www.pdai.tech/md/algorithm/alg-sort-x-shell.html 这个页面侧边点击打开后不显示内容,需要刷新下才显示数据
https://pdai.tech/md/devops/tool/tool-git.html 其中有一张图 git push -f 不是强推到远程上吗 那个箭头是指向本地分支的(若没问题 则就是我对git push -f 理解有误)
代码撤销和撤销同步 《==这个标题下的图
https://www.pdai.tech/md/interview/x-interview.html#%E4%BB%80%E4%B9%88%E6%98%AFblockingdeque-%E9%80%82%E5%90%88%E7%94%A8%E5%9C%A8%E4%BB%80%E4%B9%88%E6%A0%B7%E7%9A%84%E5%9C%BA%E6%99%AF 什么是BlockingDeque? 适合用在什么样的场景? 这个问题是Deque,回答内容是BlockingQueue
文章:CRON表达式 - CRON表达式介绍和使用 链接:https://www.pdai.tech/md/develop/cron/dev-cron-x-usage.html 原文中的错误:星期 DayofWeek 是 [1, 7]或[MON, SUN]。若使用[1, 7]表达方式,1代表星期一,7代表星期日。
1 代表的是星期日,7 代表的是星期六。
文章标题:Redis进阶 - 高可拓展:分片技术(Redis Cluster)详解 文章链接:https://pdai.tech/md/db/nosql-redis/db-redis-x-cluster.html#%E4%B8%BB%E8%A6%81%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D 错误位置:主要模块介绍-哈希槽(Hash Slot) 错误内容:每个key通过CRC16校验后对16383取模来决定放置哪个槽 更正内容:hash槽位置结算公式:HASH_SLOT = CRC16(key) mod 16384,应该是对16384进行取模。
https://www.pdai.tech/md/interview/x-interview.html#_2-2-map Java全栈知识点问题汇总(上) -> 2Java集合 -> 2.2Map Map有哪些类 第三点 是Hashtable而不是HashTable
《Redis入门 - 数据类型:3种特殊类型详解》文章,关于【什么是基数?】里的举例是不是写错了? 文章连接:https://pdai.tech/md/db/nosql-redis/db-redis-data-type-special.html#hyperloglogs%E5%9F%BA%E6%95%B0%E7%BB%9F%E8%AE%A1 原文举例: 举个例子,A = {1, 2, 3, 4, 5}, B = {3, 5, 6, 7, 9};那么基数(不重复的元素)= 1, 2, 4, 6, 7, 9; (允许容错,即可以接受一定误差)
我的理解:基数元素 = 1,2,3,4,5,6,7,9 故最终基数 = 8(通过HyperLogLog命令反正得出)
Redis入门- 数据类型: 5种基础数据类型详解 Set集合 命令使用中第三个 SMEMBERS的使用错误 应该是 SMEMBERS
https://pdai.tech/md/algorithm/alg-domain-security-degist.html#sha1 在上面这篇文章中,标题为sha1,应该跳转到sha1的百科,但是实际使仍然跳转到了md5百科
错别字问题: 时 → 是
分布式数据库时网站数据库拆分的最后手段,只用在单表数据规模非常大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务拆分,将不同业务的数据部署在不同的物理服务器上。 原文地址
https://pdai.tech/md/java/basic/java-basic-lan-basic.html#%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B
在java基础板块中的隐式类型转换中的说法“ 因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。”
有一条规则是在给byte、short、char直接赋值字面量时,这个数小于对应的变量范围是可以直接赋值的,如 byte b = 1; short s = 1; 这句话是成立的
文章标题:Redis进阶 - 高可拓展:分片技术(Redis Cluster)详解 文章连接:https://pdai.tech/md/db/nosql-redis/db-redis-x-cluster.html 错误处:哈希槽小段中,关于哈希槽基本算法写错了
Redis-cluster没有使用一致性hash,而是引入了哈希槽的概念。Redis-cluster中有16384(即2的14次方)个哈希槽,每个key通过CRC16校验后对16383取模来决定放置哪个槽。Cluster中的每个节点负责一部分hash槽(hash slot)
redis官网上给出的算法是:
HASH_SLOT = CRC16(key) mod 16384
所以,是对16384取模,而不是对16383取模。 16384个槽位,映射是从0到16383,如果是16383取模,余数不会存在16383,那么槽位16363永远不会被使用。
https://pdai.tech/md/java/thread/java-thread-x-juc-collection-ConcurrentHashMap.html 作者你好,您的网站和内容太棒了。我在《ConcurrentHashMap详解》一文中我发现了☝️问题。文中对JDK1.8中 put(...) 源码解析的注释中提到 ConcurrentHashMap Hash桶中的链表转红黑树时机和HashMap稍有不同,ConcurrentHashMap 在数组大小 < 64 时会选择数组扩容。不过,我看了下源码;ConcurrentHashMap 和 HashMap 在 treeifyBin(...) 方法里都会判断是否 < MIN_TREEIFY_CAPACITY(64),如果成立的话会选择先数组扩容。
单元测试 这里,针对service的测试,mock的应该是Repository,代码里把service给替换掉了
参数校验国际化 这里缺少一个MessageSource的路径配置,不然不太看得明白
文章:《Redis进阶 - 缓存问题:一致性, 穿击, 穿透, 雪崩, 污染等》 错误处:
更新缓存的的Design Pattern有四种:Cache aside, Read through, Write through, Write behind caching; 我强烈建议你看看这篇,左耳朵耗子的文章:缓存更新的套路
错误点:
https://www.pdai.tech/md/about/me/blog-question.html