08 JAVA 线程 内存模型(二)

本文深入探讨了Java内存模型中的volatile和synchronized关键字的工作原理,包括它们如何确保线程安全,以及如何避免重排序等问题。同时,文章还提供了一个简单的示例程序,帮助读者更好地理解这两个关键概念的应用。

一、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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值