volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性。
看下面的这段代码:
/**
*
* @author InJavaWeTrust
*
*/
public class CountVolatile implements Runnable {
public static CountVolatile instance = new CountVolatile();
public static volatile int i = 0;
public static void increate() {
i++;
}
public void run() {
for (int c = 0; c < 10000000; c++) {
increate();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
这段代码演示了一个计数器,两个线程同时对i进行累加,个执行10000000次。我们希望的执行结果是最终i的值可以达到20000000,但事实并非总是如此。很多时候,i的值会小于期望的数值20000000。这是因为两个线程同时对i进行写入时,其中一个线程的结果会覆盖另外一个线程的结果。
要从根本上解决这个问题,我们就必须保证多个线程在对i进行操作时完全同步。
关键字synchronized的作用是实现线程间的同步。当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
关键字synchronized的几种用法。
- 指定加锁对象:对给定对象加锁,进入同步代码钱要获得给定对象的锁。
- 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
- 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
一、指定加锁对象:
/**
*
* @author InJavaWeTrust
*
*/
public class CountSynchronized implements Runnable {
public static CountSynchronized instance = new CountSynchronized();
public static int i = 0;
public void run() {
for (int c = 0; c < 10000000; c++) {
synchronized(instance) { //对给定对象加锁
i++;
}
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
二、直接作用于实例方法:
/**
*
* @author InJavaWeTrust
*
*/
public class CountSynchronized2 implements Runnable {
public static CountSynchronized2 instance = new CountSynchronized2();
public static int i = 0;
public synchronized void increate() { //对当前实例方法加锁
i++;
}
public void run() {
for (int c = 0; c < 10000000; c++) {
increate();
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
三、直接作用于静态方法:
/**
*
* @author InJavaWeTrust
*
*/
public class CountStaticMethod implements Runnable {
static int i = 0;
public static synchronized void increate() { //相当于对当前类加锁
i++;
}
public void run() {
for (int c = 0; c < 10000000; c++) {
increate();
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new CountStaticMethod());//new一个对象
Thread t2 = new Thread(new CountStaticMethod());//new一个对象
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}