变量易失性
:易失关键字适用于变量。Java中的易失关键字保证易失变量的值始终从主内存中读取,而不是从线程的本地缓存中读取。
Access_Modifier volatile DataType Variable_Name;
易失性字段:向虚拟机表明多个线程可能同时尝试访问/更新字段的值。一种特殊类型的实例变量,必须在所有具有修改值的线程之间共享。类似于静态(类)变量,易失性值的唯一副本被缓存在主内存中,因此在进行任何ALU操作之前,每个线程都必须从主内存中读取更新后的值,然后在ALU操作之后直接写入主内存。(对易失性变量v的写入与任何线程后续读取v同步)这意味着对易失性变量的更改始终对其他线程可见。
如果线程t1更改了t1缓存中的值,对于非易失性变量,线程t2无法访问更改后的值,直到t1写入,并从主内存中读取最近修改的值,这可能导致数据不一致。
volatile cannot be cached - assembler
+
| Flag Name | Value | Interpretation |
+
| ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
+
|ACC_TRANSIENT | 0x0080 | Declared transient; not written or |
| | | read by a persistent object manager.|
+
共享变量
:可以在线程之间共享的内存称为共享内存或堆内存。所有实例字段、静态字段和数组元素都存储在堆内存中。
同步:synchronized 可应用于方法、块。它允许在对象上一次只执行一个线程。如果 t1 获取了控制权,则其余线程必须等待直到它释放控制权。
示例:
public class VolatileTest implements Runnable {
private static final int MegaBytes = 10241024;
private static final Object counterLock = new Object();
private static int counter = 0;
private static volatile int counter1 = 0;
private volatile int counter2 = 0;
private int counter3 = 0;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
concurrentMethodWrong();
}
}
void addInstanceVolatile() {
synchronized (counterLock) {
counter2 = counter2 + 1;
System.out.println( Thread.currentThread().getName() +"\t\t « InstanceVolatile :: "+ counter2);
}
}
public void concurrentMethodWrong() {
counter = counter + 1;
System.out.println( Thread.currentThread().getName() +" « Static :: "+ counter);
sleepThread( 1/4 );
counter1 = counter1 + 1;
System.out.println( Thread.currentThread().getName() +"\t « StaticVolatile :: "+ counter1);
sleepThread( 1/4 );
addInstanceVolatile();
sleepThread( 1/4 );
counter3 = counter3 + 1;
sleepThread( 1/4 );
System.out.println( Thread.currentThread().getName() +"\t\t\t\t\t « Instance :: "+ counter3);
}
public static void main(String[] args) throws InterruptedException {
Runtime runtime = Runtime.getRuntime();
int availableProcessors = runtime.availableProcessors();
System.out.println("availableProcessors :: "+availableProcessors);
System.out.println("MAX JVM will attempt to use : "+ runtime.maxMemory() / MegaBytes );
System.out.println("JVM totalMemory also equals to initial heap size of JVM : "+ runtime.totalMemory() / MegaBytes );
System.out.println("Returns the amount of free memory in the JVM : "+ untime.freeMemory() / MegaBytes );
System.out.println(" ===== ----- ===== ");
VolatileTest volatileTest = new VolatileTest();
Thread t1 = new Thread( volatileTest );
t1.start();
Thread t2 = new Thread( volatileTest );
t2.start();
Thread t3 = new Thread( volatileTest );
t3.start();
Thread t4 = new Thread( volatileTest );
t4.start();
Thread.sleep( 10 );;
Thread optimizeation = new Thread() {
@Override public void run() {
System.out.println("Thread Start.");
Integer appendingVal = volatileTest.counter2 + volatileTest.counter2 + volatileTest.counter2;
System.out.println("End of Thread." + appendingVal);
}
};
optimizeation.start();
}
public void sleepThread( long sec ) {
try {
Thread.sleep( sec * 1000 );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
静态[类字段
] vs 易失性[实例字段
] - 两者都不被线程缓存
@see
Sets true: value=true target=true
和Sets false: value=false target=false
,但是:大量情况可能会导致相同的输出... 尝试在blogspot上发布相同内容,但“评论仅限于团队成员”。 - Vlad