《Java并发编程的艺术》勘误和支持
第一版第一次印刷勘误
第2页,thread.join();这句代码和上面一行代码交换位置。
第3页,第一个表格“并发比串行快多少”的第五行,慢=>差不多。
第9页,表2-1第三行缓存行。第一个缓存=》CPU高速缓存,缓存线=》缓存行,
第9页,表2-1第三行缓存行。需要使用多个主内存读周期=》现代CPU需要执行几百次CPU指令
第18页,代码少了第一行 public class Counter {
第一版第二次印刷勘误
第一版第三次印刷勘误
第一版第四次印刷勘误
- 第168页LinkedBlockingQueue 有界阻塞队列 修改成 无界阻塞队列。
- 第5页的源码,DeadLockDemo里面 private static String A = “A”; 这一行的private拼写少了个e。
- 第112页的源码,work.get(count)后面少了个分号;。
- 第186页的源码,代码第2、3行,user应改为User。
- 第210页的图,图10-2左上角的类应该是Runnable;图10-3中有2个create漏了字母e,1个execute漏了字母2(找晓明修改下)
18页代码少了第一行public class Counter {
76页表3-9把表3-8复制了一遍,完全错误
多谢勘误
另外问下哪可以下载程序源码呢
有几个地方代码都不全…
并发网可以下载
76页表3-9修正的结果希望贴出来
第5页的源码,DeadLockDemo里面 private static String A = “A”; 这一行的private拼写少了个e
请问,37页的图中的读事物写的是读高32位,是不是应该改为读整个long型变量
210页,图10-2左上角的类应该是Runnable;图10-3中有2个create漏了字母e,1个execute漏了字母2
186页,代码第2、3行,user应改为User
112页,代码倒数第12行,漏掉了分号
31页, 第五行, volaLile 拼写错误, 应该是volatile
5页,1.2死锁代码,2个重写Runnable接口的run方法都写成了publicvoid,两个关键字之间缺少空格。
164页最后一行,应该是“如果p的next节点是null”吧。
59页,第三章,3.6.5标题,“溢出”==》“逸出”
69,第三种,3.8.2第一行,(instance=new Singleton();),实际上例子给的是(instance= new Instance():)
虽然么有回复,但是我要继续报错:)
第五章,5.2.2中5.自定义同步组件-TwinsLock部分,关于资源数的描述部分,“status为2”应该是“state为2”。
第六章, 6.1.3的2.初始化segmentShift和segmentMask,其中”segmentSHift最大值是16″,不是最大值,是最小值。
第三页
Content Switch –> Context Switch
魏老师,请教一个问题,第四章最后【基于线程池的简单Web服务器】的demo,server启动之后,URL如何写呢?basepath = ‘F:\\workspace’
你好 ,第4.4.4小节,115页 代码中 out.flush() 应该在socket.getOutputStream().write(array,0,array.length);之前调用,
否则,内容会先于报文头发送。
338页
“因为CyclicBarrier设置了拦截线程的数量是2,所以必须等代码中的第一个线程和线程A 都执行完之后,才会继续执行主线程,然后输出2,所以代码执行后的输出如下。”
逻辑应该是A线程一定是先执行的,但第一个线程和主线程的执行顺序是不一定的。所以执行的结果应该3、2、1或是3、1、2
您好,第12页,第5行,第8行的Synchronized拼写错误,被拼成了Synchonized
对P134页的TwinsLock的unlock方法存疑
public boolean tryReleaseShared(int returnCount) {
for(;;) {
int current = getState();
int newCount = current + returnCount;
if(compareAndSetState(current, newCount)) {
return ture;
}
}
}
unlock方法及调用方法,都没有对当前线程进行判断,判断其是否持有锁,我觉得应该加上这个判断,因为只有持有所得线程才能释放锁
而且误操作,会导致整个锁状态处于异常状态
同理P123的Mutex类
不好意思哇,以上言论全部有误,个人没法删除,麻烦管理员帮忙删除下,以防误导其他人,谢啦
刚看书到第3页,看过表1-1的表格后,有点不太懂。
书上说当执行并发累加不超过百万时,速度要比串行要慢。
为什么超过百万时,并行的速度要快近一倍呢?是不是CPU的双核同时运行的结果。如果在单核CPU上,分时调度的结果一定是慢的啊。
请各位大神给予解答,谢谢。
没有人回复?
是在多核电脑上跑的。
文字错误
P147
表5-12
对比项列“当前线程释放锁并进入等待状态,在等待状态中不响应中断”疑似错误
应该为“当前线程释放锁并进入等待状态,在等待状态中响应中断”
多了个“不”字
不好意思哇,以上言论再次全部有误,个人没法删除,麻烦管理员帮忙删除下,以防误导其他人,谢啦 🙁
版次: 2016年10月份第一版第六次印刷
第七章 java中的13个原子操作类
只有12个,在7.2原子更新数据AtomicIntegerArray重复
表1-1测试结果中:循环次数为10万次的这行,并发比串行快多少的结果应该是“快”吧???
您好,正在拜读该书。43页给予保守策略的…..屏障插入策略。下面4点,最后两条有2个volatile读操作后,的规则。是不是应该有一个是读前,一个是读后
是我理解错误,没看到下面的内容,请忽略这个反馈。抱歉
倒数第二个,应该是:在每个volatile读操作的前面插入一个LoadLoad屏障吧。没看明白
看到P44图,明白了。ps:网上一些博文都是写的前面,跟本书不一致。
你好,目前正在拜读该书,发现一个问题
版次:2016年4月第1版第5次印刷
描述:第2章,第10页的第7行,提到8.1.4节,但我没在该书中找到相应的的章节,不知是不是印刷的问题,如果是,那么应该是哪个章节
第一版第一次印刷
146页第四行“RentrantReadWriteLock”少了个e
01,案例代码太简单,排版不好
02,注释有很多欠缺,并且注释有的地方很晦涩
ScheduledThreadPoolExecutor, ThreadPoolExecutor, 作者你確定都有submit()方法,10章裏面很多地方這樣寫,比如p212
您好,版次:2017年7月第1版第9次印刷,P134,TwinsLock中的tryAcquireShared(int reduceCount)方法,缺少返回语句。
Sorry, 是我大意了。
版次:2017年7月第1版第9次印刷,P158,“segmentShift等于32减sshift,所以等于28。”和后边的“所以segmentShift最大值是16”前后矛盾
P193,代码清单8-4的执行结果还有一种可能是3 2 1,只等线程A,并不等待第一个线程
P39,有部分内容让我感到疑惑,原书内容如下:
简而言之,volatile变量自身具有下列特性。
…
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不
具有原子性。
在我的理解中 volatile 不是只能保证变量的可见性,不能保证其原子性吗?
希望作者能帮助解答,非常谢谢!
您好:正在拜读 并发编程的艺术
关于第3章JMM中 3.1.4小节中的 表3.3 内存屏障类型表 有些不明白的地方
1.关于4中类型的屏障 涉及到的 Load 指令是否是指从主存中读取更新线程自己的工作内存中
2.Load1 LoadLoad Load2 屏障中的Load1 指的是一条load指令 还是屏障上面的涉及到的所有Load 指令
3.Store1 StoreLoad Load2 屏障 书中描述会把屏障之前的store操作刷新到主存 那么是否也会把storeLoad屏障之前的Load 从主存中加载到工作线程中 。
尊敬的作者:
您好!我正在拜读您的《Java并发编程的艺术》,第四章的4.2.3 理解中断一节,Interrupted程序的执行结果与书中的并不一致,SleepThread程序的打印结果为:SleepThread interrupted is true。不知是否是在java12.0.1版本对InterrupedException抛出之前清除中断标志位的机制修改了,还请在您有时间的时候解答以下。
尊敬的作者:
您好!我正在拜读您的《Java并发编程的艺术》,正如您在4.1.5 Daemon线程一节所说的,不能把执行关闭或者清理资源的逻辑放到Daemon线程的finally块中。
然而,在第5章第5节——自定义同步组件,在程序TwinsLockTest.java程序中,在Worker的finally块中使用了lock.unlock();语句,这样做的理由是什么呢?
作者您好,我正在读这本书,我发现第52页,也就是3.5.3节,其中ReentrantLock的unlock()方法的调用轨迹顺序写错了,应该先Sync:release(int arg),然后AQS:tryRelease(int releases)。
你好,我刚也在看这节,我看的JDK8的源码,作者写的我觉得没有错,因为Sync抽象类是继承AQS的,所以作者说先调用AQS的方法应该也可,在调用链的最后,调用了ReentrantLock的静态内部类sync的方法tryRelease,因为静态内部类Sync继承AQS,重写了tryRelease方法,所以最后调用的是Sync的tryRelease方法
题主我重新整理下ReentrantLock的unlock()方法的调用链,觉得和书上写的吻合,unlock方法调用其静态内部类Sync的release()方法,此方法没有重写,实际是调用AQS的release方法,之后在AQS的release方法内调用了ReentrantLock的静态内部类Sync重写的tryRelease方法,所以顺序是1.ReentrantLock.lock() 2.AQS.release() 3.Sync.tryRelease(),公平锁和非公平锁的调用链相同
volatile写前面加StoreStore内存屏障,可以禁止volatile前面的普通写和volatile变量重排序,但是普通读变量感觉是没有办法禁止重排序的?
个人认为是volatile写后面加的storeload屏障保证了写之前的所有操作对之后的读操作可见(实现是禁止了写之前的所有操作重排序到写之后,包括普通读变量的操作)
你好。2018年10月第一版第13次印刷,158页 2.初始化segmentShift和segmentMask 本段的倒数第二行。“所以segmentShift”最大值16 应该是最小值是16吧。
作者,您好,请教个问题,书中85页到86页里的代码清单4-2 Priority.java中,Job.jobCount这个字段如何保证可见性的?
第八章Java中的并发工具类-8.4线程交换数据的Exchanger。 代码8-8 ExchangerTest的代码。图中标注的位置B 不能加引号,否则交换的内容就错了
第三章中3.8.4基于类初始化的解决方案的小节中发现:在类初始化—第3阶段的执行时序表(表3.-9)与图3-43 类初始化-第3阶段的图不符合。
在第三章中3.8.4基于类初始化的解决方案的小节中发现:在类初始化—第3阶段的执行时序表 。表3-9 与表3-8(类初始化-第2阶段的执行时序图)是一模一样的。应该是 有区别的,图错了
刚读到这部分类容,发现表格一致,虽然没有官方解释,但从图能猜个大概。
2019年11月第1版第16次印刷,第43页,中间偏上位置。
在每个volatile读操作的后面插入一个LoadLoad屏障。
应该是在前面吧,后两条都是在后面。
在每个volatile读操作的后面插入一个LoadLoad屏障。
在每个volatile读操作的后面插入一个LoadStore屏障。
没错的,是我没理解,抱歉,打扰了。
有volatile变量修饰的共享变量进行写操作的时候会多出第二行汇编代码,通过查IA-32架
构软件开发者手册可知,Lock前缀的指令在多核处理器下会引发了两件事情[1]。
1)将当前处理器缓存行的数据写回到系统内存。
2)这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。
这个2是如何使其他cpu里的缓存无效的呢
看到只有这个解释
为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部
缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile的
变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据
写回到系统内存。但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操
作就会有问题。所以,在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一
致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当
处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状
态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存
里。
第112页,不只是少了一个分号,workers.remove(worker) 之后 workers 数组长度会变小,使用workers.get(count) 明显会下标越界。
飞哥你好: 最近在看您的《java并发编程艺术》一书;有一些个人感觉可能存在问题的地方。
一:在读写锁实现章节中代码清单5-19 processData方法代码上感觉有点漏洞,如果在第二个获取读锁前抛出异常;这样第二个读锁释放锁就会出问题;个人感觉可以修改如下:
public void lockDowngrade() {
// 注意这里的
readLock.lock();
try {
System.out.println(“当前线程获取写锁”);
writeLock.lock();
try {
System.out.println(“准备获取读锁,进行数据操作”);
} finally {
System.out.println(“释放写锁,如果当前线程获取有读锁,锁降级”);
readLock.lock();
readLock.unlock();
writeLock.unlock();
}
System.out.println(“降级读锁操作”);
} finally {
System.out.println(“释放读锁”);
readLock.unlock();
}
}
二: FutureTask 现在的源码中对锁的实现不是利用的AQS了;可以将代码更新下;而是利用的AQS 原理自己维护了一个阻塞队里;在利用共享锁和条件锁实现的强占和唤醒。
您好!在本书的109页中的 ConnetionRunner 是不是应该是 ConnectionRunner.虽然不影响程序的正常运行,但是作为一本颇有影响力的书籍应该单词拼写正确的。
还有个建议就是 希望能够在实现接口或者继承的时候,是的方法也好,还是重写的也好,能够按照规范加上 @Override 这样更加能清楚的区分。
作者您好!
书中213页,DefaultThreadPool中的p
ublic void removeWorker(int num) {
synchronized (jobs) {
if (num >= this.workerNum) {
throw new IllegalArgumentException(“beyond workNum”);
}/
/ 按照给定的数量停止Worker
int count = 0;
while (count < num) {
Worker worker = workers.get(count)
if (workers.remove(worker)) {
worker.shutdown();
count++;
}
}t
his.workerNum -= count;
}
}方法是否存在workers.get(count)数组下标越界呢
作者你好!
请教一个问题,在代码清单4-16 ConnectionPool.java中,fetchConnection函数的超时等待模式实现,使用while循环的意义在哪里?
在知道超时等待的时间之后,调用pool.wait(remaining)本身不就具备了超时等待的功能吗?此函数调用返回无非2种情况:1)等待时间超时;2)持有pool监视器的其他线程调用notify/notifyAll函数,并释放了监视器。第1种情况下,remaining会被更新为0,直接就跳出循环。第2种情况下,pool中被放回了一个元素,肯定也不为空,同样会跳出循环。这样的话,while循环其实都会仅被执行1次。为什么不能直接通过调用pool.wait(remaining)函数来实现呢?
不知道我的理解对不对,望不吝答疑,感谢!
作者,您好
在阅读到第4章,4.1.4线程的状态,图4-1 java线程状态变迁。waiting线程经过Object.notify()后状态变为runnable。
我在网上找到一些资料:
资料1:https://www.uml-diagrams.org/java-thread-uml-state-machine-diagram-example.html
资料2:https://stackoverflow.com/questions/28378592/java-thread-state-transition-waiting-to-blocked-or-runnable
在资料1中的图片,waitting线程调用被notify后的状态是blocked。
资料2中相应的回答,也表明了waitting线程调用被notify后的状态是blocked
所以,跟《java并发编程的艺术》的内容有矛盾的地方。
望作者答疑,谢谢。
20页
3.1.1 最后两段
同步是指程序中用于控制不同线程间操作发生相对顺序的机制。在【共享内存并发模型里,同步是显式进行的】。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。在消息传递模型的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。
【Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式进行】,整个通信过程对程序员完全透明。如果编写多线程程序的Java程序员不理解隐式进行的线程之间通信的工作机制,很可能会遇到各种奇怪的内存可见性问题。
——————————–
如上两端文字,两个【】包裹之间的内容自相矛盾。显然大家可能也知道我大lowb java是基于共享内存模型显式通信的。但自相矛盾的文字容易对新手造成一定影响。
2.1 volatile的应用
1.volatile的定义与实现原理
1)Lock前缀指令会引起处理器缓存回写到内存
“如果访问的内存区域已经缓存在处理器内部,则不会声言LOCK#信号。”——我不确定“声言”对不对,感觉应该是“声明”?
我也觉得这里有问题…也没查到声言这个词
多字或者缺字
p136 5.3重入锁
第一自然段第二行
“除此之外,该锁【的】还支持获取锁时的公平和非公平性选择”。
作者您好,请问43页提到的JMM内存屏障插入策略中:
在每个volatile读操作的后面插入一个LoadLoad屏障。
在每个volatile读操作的后面插入一个LoadStore屏障。
这两句话中是否有一句‘后面’应改为‘前面’呢?