本文主要是介绍一篇讲双锁检测的文章,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
问题来源于群里面一个同学发了一篇关于双锁检测的文章,然后就有人反对说,双锁检测是过时的。于是乎,我也去找了一下相关的文章。http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html,这一篇文,就是发到群里面的文章。
虽然这篇文章说了在1.5之后,可以使用final字段让对象完全初始化。但是,并没有说明,如果我们使用普通的成员变量,会不会造成对象半初始化对象。这里有一个共同的前提,就是这个被初始化对象是volatile类型。当时本人就给定了一个结论说如果被初始化对象包含普通类型字段(非final和volatile),那么,双锁检测一定是失败的,造成未完全初始化的对象。所以当时这个结论就错了,参考这篇文章http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html对新java内存模型的解读
Under the old memory model, accesses to volatile variables could not be reordered with each other, but they could be reordered with nonvolatile variable accesses. This undermined the usefulness of volatile fields as a means of signaling conditions from one thread to another.
Under the new memory model, it is still true that volatile variables cannot be reordered with each other. The difference is that it is now no longer so easy to reorder normal field accesses around them. Writing to a volatile field has the same memory effect as a monitor release, and reading from a volatile field has the same memory effect as a monitor acquire. In effect, because the new memory model places stricter constraints on reordering of volatile field accesses with other field accesses, volatile or not, anything that was visible to thread A when it writes to volatile field f becomes visible to thread B when it reads f.
故事永远不是这么简单的结束的,结束实际上来源于两段诡异的代码。大致意思是,一个线程不断的创建ArrayList赋值给一个全局变量,另外几个线程同时读取这个ArrayList并调用add方法,那么在-server的jit编译下,会导致nullPointexception,如果对这个全局数组加上volatile,那么就不会抛这个异常出来(参考代码片段2)。
另外一段代码就是模拟,工作线程copy 主内存的Integer,然后另一个线程不断给Integer赋值null,同样不会报错。这里有个技巧||和&&的区别。(参考代码片段1)
这里插上两段代码--
1.不会报错,因为max被copy到工作线程,当max加上volatile时,可以看到直接出错,因为max为null
public class Main {public static Integer max = null;public static void main(String[] args){Thread[] threads = new Thread[20];for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(new Runnable() {@Overridepublic void run() {while (true) {if(max == null || max > 10){max = 10;}}}});threads[i].start();}Thread t1 = new Thread(){public void run(){while(true){max = null;}}};t1.start();}
}
</pre><span style="background-color: rgb(0, 0, 0);"></span><pre name="code" class="java">public class Test {public static List<String> l = new ArrayList<String>(1024); public static void main(String[] args) {
Thread[] threads = new Thread[20];for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(new Runnable() {@Overridepublic void run() {int j = 0;while (true) {synchronized (HmacSHA1.class) {if(l.size() < 1024)l.add("ttt");}}}});threads[i].start();}Thread t1 = new Thread(){public void run(){while(true){List<String> local = l;l = new ArrayList<String>(1024);}}};t1.start();}}
这篇关于一篇讲双锁检测的文章的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!