一、volatile
相当于对某个变量读写的原子操作,写就是修改数据后刷入主内存,而读就是把线程对应的本地内存置为无效,然后从主内存中读取共享变量~
Assuming there are two threads A and B:
- 当线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了消息
- 线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的消息
- 线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过主内存向线程B发送消息
volatile特性:
- 读写原子性,但是对于像volatile++这样复合操作不具有原子性
public class TestVolatile {
public volatile int i = 0;
public void set(int i) {
this.i = i;
}
/*
* public synchronized void set(int i) {
this.i = i;
}
*/
public int get() {
return i;
}
/*
* public int get() {
return i;
}
*/
public void increI() {
i++;
}
/*
* public void increI() {
int tmp = get();
tmp++;
set(tmp);
}
*/
}
volatile与重排序:
- 当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序
- 当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序
- 当第一个操作是volatile写时,第二个操作是volatile读时,不能重排序
二、synchronized
Assuming there are two threads A and B:
- 线程A释放了一个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了消息
- 线程B获取一个锁,实质上是线程B接收了之前某个线程发出的消息
- 线程A释放锁,虽然线程B获取这个锁
synchronized也可以用来使run方法同步,run方法同时只能被一个线程调用,而且当前的run执行完后,才被其他线程调用。它由以下几个特性:
1. synchronized关键字不能继承,因为他不属于方法定义的一部分
2. 定义接口方法时不能使用
3. 在非静态方法中,可以放在方法定义的最前面,但是不能放置于方法返回类型的后面
4. 不能用来同步类变量
import java.util.*;
class Runner_1 {
int a = 0;
volatile boolean flag = false;
//boolean flag = false;
//锁住当前对象,只有一个线程可以访问该区域程序,同时别的synchronized方法不能执行,因为必须获得锁才可以执行
//public synchronized void writer() {
public void writer() {
a ++;
System.out.println("p1");
//对于volatile变量,还未被写入主内存之前,不能有另一个线程来修改
flag = true;
System.out.println("p3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("p5");
}
public void reader() {
System.out.println("p2");
if(flag) {
//第一个操作是volatile读的时候,不能重排序
System.out.println(a);
}
System.out.println("p4");
}
}
public class Thread1 extends Thread {
Runner_1 r1;
Thread1(Runner_1 r1) {
this.r1 = r1;
}
public void run() {
r1.writer();
}
}
public class Thread2 extends Thread {
Runner_1 r1;
Thread2(Runner_1 r1) {
this.r1 = r1;
}
public void run() {
r1.reader();
}
}
public class TestThread1 {
public static void main(String[] args) {
Runner_1 r = new Runner_1();
Thread1 td = new Thread1(r);
//Thread1 td1 = new Thread1(r);
Thread2 td1 = new Thread2(r);
td.start();
td1.start();
}
}
import java.util.concurrent.*;
public class Thread1 {
private static /*volatile*/ boolean stop = false;
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stop) {
i++;
//System.out.println("hello");
}
}
});
t.start();
Thread.sleep(1000);
TimeUnit.SECONDS.sleep(1);
System.out.println("Stop Thread");
stop = true;
}
}Reference:
1. 深入理解JAVA内存模型
2. http://marlonyao.iteye.com/blog/636599
本文深入探讨了Java内存模型中的volatile和synchronized关键字的工作原理,包括它们如何确保线程安全,以及如何避免重排序等问题。同时,文章还提供了一个简单的示例程序,帮助读者更好地理解这两个关键概念的应用。

被折叠的 条评论
为什么被折叠?



