java原始的int是primefacesdevise还是意外?

是原始的java原始整数(int)primefaces吗? 对两个共享int的线程的一些实验似乎表明它们 ,但是当然没有证据表明它们并不意味着它们是。

具体来说,我跑的testing是这样的:

public class IntSafeChecker { static int thing; static boolean keepWatching = true; // Watcher just looks for monotonically increasing values static class Watcher extends Thread { public void run() { boolean hasBefore = false; int thingBefore = 0; while( keepWatching ) { // observe the shared int int thingNow = thing; // fake the 1st value to keep test happy if( hasBefore == false ) { thingBefore = thingNow; hasBefore = true; } // check for decreases (due to partially written values) if( thingNow < thingBefore ) { System.err.println("MAJOR TROUBLE!"); } thingBefore = thingNow; } } } // Modifier just counts the shared int up to 1 billion static class Modifier extends Thread { public void run() { int what = 0; for(int i = 0; i < 1000000000; ++i) { what += 1; thing = what; } // kill the watcher when done keepWatching = false; } } public static void main(String[] args) { Modifier m = new Modifier(); Watcher w = new Watcher(); m.start(); w.start(); } } 

(这只是在32位Windows PC上用java jre 1.6.0_07试过)

本质上,修饰符将计数序列写入共享整数,而观察器检查观察值是否永远不会下降。 在32位值必须作为四个独立字节(或甚至两个16位字)访问的机器上,Watcher将会以不一致的半更新状态捕获共享整数,并检测到值降低而不是增加。 无论(假设的)数据字节是收集/写入LSB 1st还是MSB 1st,这都应该起作用,但最好只是概率性的。

在今天的宽数据path中,看起来很有可能32位值可能是有效primefaces的,即使java规范不需要它。 实际上,对于一个32位的数据总线来说,似乎你可能需要更努力地获得字节访问比32位整数。

使用“java原始线程安全性”来search线程安全的类和对象,但是寻找关于原语的信息似乎正在寻找大海捞针。

Java中的所有内存访问都是默认的primefaces,除了longdouble可能是primefaces的,但不一定是)。 说实话不是清楚,但我相信这就是暗示。

从JLS 第17.4.3节 :

在顺序一致的执行中,对于与程序顺序一致的所有单独操作(例如读取和写入)存在全部顺序,并且每个单独的操作是primefaces的并且对于每个线程立即可见。

然后在17.7 :

有些实现可能会发现将64位long或double值的单个写入操作划分为相邻32位值的两个写入操作是很方便的。 为了提高效率,这个行为是特定于实现的; Java虚拟机可以自由地执行写入长和双值的primefaces或两部分。

请注意,虽然primefaces性与波动性非常不同。

当一个线程将整数更新为5时,保证另一个线程不会看到1或4或其他任何中间状态,但是没有任何明确的波动或locking,另一个线程可以永远看到0。

关于努力获得primefaces访问字节,你是对的:虚拟机可能不得不努力尝试…但它必须。 从规范的第17.6节 :

某些处理器不提供写入单个字节的function。 通过简单地读取整个字,更新适当的字节,然后将整个字写回存储器,在这样的处理器上实现字节arrays更新是非法的。 这个问题有时被称为字撕裂,在处理器上不能轻易更新一个单独的字节孤立一些其他的方法将是必需的。

换句话说,这是由JVM来做正确的。

  • 没有任何testing可以certificate线程安全 – 它只能反证它;
  • 我在JLS 17.7中find了一个间接的参考

有些实现可能会发现将64位long或double值的单个写入操作划分为相邻32位值的两个写入操作是很方便的。

并进一步下降

对于Java编程语言内存模型而言,对非易失性long或double值的单个写入被视为两个独立的写操作:每个32位一半。

这似乎意味着写入整数是primefaces的。

我认为它不像你预期的那样工作:

 private static int i = 0; public void increment() { synchronized (i) { i++; } } 

整数是不可变的,所以你一直在不同的对象同步。 int“我”是自动转到Integer对象,然后你设置locking它。 如果另一个线程进入这个方法int我自动绑定到另一个Integer对象,然后你设置一个不同的对象然后再locking。

我同意Jon Skeet的观点,我想补充一点,很多人混淆了primefaces性,波动性和线程安全的概念,因为有时这些术语可以互换使用。
例如,考虑一下:

 private static int i = 0; public void increment() { i++; } 

虽然有人可能会认为这个操作是primefaces的,但所提的假设是错误的。
声明i++; 执行三个操作:
1)阅读
2)更新
3)写

因此,对这个variables进行操作的线程应该像这样同步:

 private static int i = 0; private static final Object LOCK = new Object(); public void increment() { synchronized(LOCK) { i++; } } 

或这个:

 private static int i = 0; public static synchronized void increment() { i++; } 

请注意,对于单个对象实例,调用多个线程正在访问的方法并对共享可变数据进行操作时,必须考虑到每个线程的方法参数,局部variables和返回值都是本地的。

欲了解更多信息,请查看此链接:
http://www.javamex.com/tutorials/synchronization_volatile.shtml

希望这可以帮助。

更新 :也有可以在类对象本身上进行同步的情况。 更多的信息在这里: 如何同步一个静态variables之间运行Java类中的不同类的实例的线程?

从整数或任何更小types的读或写应该是primefaces的,但正如罗伯特所指出的,longs和double可能会或可能不会取决于实现。 但是,使用读取和写入操作(包括所有增量操作符)的任何操作都不是primefaces操作。 因此,如果你必须在一个整数i = 0上运行的线程,那么i ++和另一个i = 10,结果可能是1,10或11。

对于像这样的操作,你应该看看AtomicInteger ,它具有在检索旧值或自动递增值时自动修改值的方法。

最后,线程可能会cachingvariables的值,并不会看到从其他线程对其进行的更改。 为了确保两个线程总是看到另一个线程所做的更改,您需要将该variables标记为volatile。

这有点复杂,并且与系统话语相关。 Bruce Eckel更详细地讨论它: Java线程 。

primefaces读取和写入仅仅意味着你永远不会读,例如一个int更新的前16位和另一个旧值。

当其他线程看到这些写入时什么都没说。

长话短说,当两个线程在他们之间没有记忆障碍竞争时,就会有东西丢失。

旋转两个或更多的线程,增加一个共享的整数,也可以计算自己的增量。 当整数达到某个值(INT_MAX,例如,好的和大的让事情变暖)停止一切,并返回int的值和每个线程执行的增量数。

  import java.util.Stack; public class Test{ static int ctr = Integer.MIN_VALUE; final static int THREADS = 4; private static void runone(){ ctr = 0; Stack<Thread> threads = new Stack<>(); for(int i = 0; i < THREADS; i++){ Thread t = new Thread(new Runnable(){ long cycles = 0; @Override public void run(){ while(ctr != Integer.MAX_VALUE){ ctr++; cycles++; } System.out.println("Cycles: " + cycles + ", ctr: " + ctr); } }); t.start(); threads.push(t); } while(!threads.isEmpty()) try{ threads.pop().join(); }catch(InterruptedException e){ // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(); } public static void main(String args[]){ System.out.println("Int Range: " + ((long) Integer.MAX_VALUE - (long) Integer.MIN_VALUE)); System.out.println(" Int Max: " + Integer.MAX_VALUE); System.out.println(); for(;;) runone(); } } 

这是在我的四核心盒子上的testing结果(随意使用代码中的线程数,显然我只是匹配了我的核心数):

 Int Range: 4294967295 Int Max: 2147483647 Cycles: 2145700893, ctr: 76261202 Cycles: 2147479716, ctr: 1825148133 Cycles: 2146138184, ctr: 1078605849 Cycles: 2147282173, ctr: 2147483647 Cycles: 2147421893, ctr: 127333260 Cycles: 2146759053, ctr: 220350845 Cycles: 2146742845, ctr: 450438551 Cycles: 2146537691, ctr: 2147483647 Cycles: 2110149932, ctr: 696604594 Cycles: 2146769437, ctr: 2147483647 Cycles: 2147095646, ctr: 2147483647 Cycles: 2147483647, ctr: 2147483647 Cycles: 2147483647, ctr: 330141890 Cycles: 2145029662, ctr: 2147483647 Cycles: 2143136845, ctr: 2147483647 Cycles: 2147007903, ctr: 2147483647 Cycles: 2147483647, ctr: 197621458 Cycles: 2076982910, ctr: 2147483647 Cycles: 2125642094, ctr: 2147483647 Cycles: 2125321197, ctr: 2147483647 Cycles: 2132759837, ctr: 330963474 Cycles: 2102475117, ctr: 2147483647 Cycles: 2147390638, ctr: 2147483647 Cycles: 2147483647, ctr: 2147483647 

这不是primefaces的:

 i++; 

但是,这是:

 i = 5; 

我认为这是一些混乱的地方。