一、异常情况
500个线程同时操纵变量number,执行number++操作,结果并不一定等于500。
无论是否使用volatile 修饰number,结果都一样。
public class VolatileTest {
public static volatile int number = 0;
public void increase(){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
number++;
}
public static void main(String[] args) {
final VolatileTest test = new VolatileTest();
for(int i = 0 ; i < 500 ; i++){
new Thread(new Runnable() {
@Override
public void run() {
test.increase();
}
}).start();
}
//若当期依然有子线程没有执行完毕
while(Thread.activeCount() > 2){
//使得当前线程(主线程)让出CPU时间片
Thread.yield();
}
System.out.println("number is " + number);
}
}
二、改进方式
2.1使用synchronized
public void increase(){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(this){
number++;
}
}
2.2使用ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class VolatileTest {
public static int number = 0;
public Lock lock = new ReentrantLock();
public void increase(){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
try{
number++;
}finally{
lock.unlock();
}
}
public static void main(String[] args) {
final VolatileTest test = new VolatileTest();
for(int i = 0 ; i < 500 ; i++){
new Thread(new Runnable() {
@Override
public void run() {
test.increase();
}
}).start();
}
//若当期依然有子线程没有执行完毕
while(Thread.activeCount() > 2){
//使得当前线程(主线程)让出CPU时间片
Thread.yield();
}
System.out.println("number is " + number);
}
}
2.3 AtomicInteger
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口
import java.util.concurrent.atomic.AtomicInteger;
public class VolatileTest {
public static AtomicInteger number = new AtomicInteger(0);
public void increase(){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
number.getAndIncrement();//获得当前值并且加1
}
public static void main(String[] args) {
final VolatileTest test = new VolatileTest();
for(int i = 0 ; i < 500 ; i++){
new Thread(new Runnable() {
@Override
public void run() {
test.increase();
}
}).start();
}
//若当期依然有子线程没有执行完毕
while(Thread.activeCount() > 2){
//使得当前线程(主线程)让出CPU时间片
Thread.yield();
}
System.out.println("number is " + number);
}
}
三、volatile适用情况
对变量的写入操作不依赖当前值比如自增自减、number = number + 5等(不满足)
当前volatile变量不依赖于别的volatile变量
比如 volatile_var > volatile_var2这个不等式(不满足)
四、synchronized和volatile比较
volatile不需要同步操作,所以效率更高,不会阻塞线程,但是适用情况比较窄
volatile读变量相当于加锁(即进入synchronized代码块),而写变量相当于解锁(退出synchronized代码块)synchronized既能保证共享变量可见性,也可以保证锁内操作的原子性;volatile只能保证可见性