线程同步synchronized和volatile

来源:互联网 发布:大数据时代的重要性 编辑:程序博客网 时间:2024/06/04 23:19

java多线程特性

线程同步具有两个特性:可见性和有序性
java线程间的通信是通过共享变量实现的,假如多个线程共享某个Object对象,该对象被创建在主内存(堆内存)中,每个线程都有自己的工作内存(线程栈). 当线程操作Object对象时,首先从主内存拷贝对象副本到工作内存中,再执行修改变量的代码,最后把工作内存中的Object刷新到主内存中. 假如多个线程都保留Object对象的副本,若某时刻修改Object变量,其他线程也能够看到被修改后的值,此为可见性. 多线程并发执行时,cpu对线程的调度是随机的,最经典的例子是银行汇款问题,我们需要保证取款线程和汇款线程有序的进行,此为有序性.

synchronized

下面用代码说明线程同步的问题

public class TraditionalThreadSynchronized {    public static void main(String[] args) {        final Outputter output = new Outputter();        new Thread() {            public void run() {                output.output("zhangsan");            };        }.start();              new Thread() {            public void run() {                output.output("lisi");            };        }.start();    }}class Outputter {    public void output(String name) {        // TODO 为了保证对name的输出不是一个原子操作,这里逐个输出name的每个字符        for(int i = 0; i < name.length(); i++) {            System.out.print(name.charAt(i));            // Thread.sleep(10);        }    }}

程序的运行结果为zhlainsigsan,显然与预期结果不相符,这就是线程同步问题. 我们希望线程执行完output方法后再切换到其他线程. java使用synchronized关键字保证某段代码在不同线程间的执行是互斥的.

  • 使用synchronized将需要互斥的代码块包含起来
{    synchronized (this) {        for(int i = 0; i < name.length(); i++) {            System.out.print(name.charAt(i));        }    }}
  • synchronized加在需要互斥的方法上
public synchronized void output(String name) {    // TODO 线程输出方法    for(int i = 0; i < name.length(); i++) {        System.out.print(name.charAt(i));    }}

这种方式相当于用this锁住整个方法内的代码块,当修饰静态方法时,等价于用xxx.class锁住整个方法内的代码块,用synchronized修饰的代码块可以看做原子操作.
线程执行互斥方法的过程如下:
1. 获取同步锁
2. 清空工作内存
3. 从主内存拷贝对象副本到工作内存
4. 执行代码
5. 刷新主内存
6. 是放同步锁

由此可见synchronized既保证共享内存的可见性,又保证程序的有序性.

volatile

volatile是第二种java实现线程同步的机制.

class Test {    static volatile int i = 0, j = 0;    static void one() {        i++;        j++;    }    static void two() {        System.out.println("i=" + i + " j=" + j);    }}

one方法和two方法还会并发执行,但加上volatile修饰后,可以将共享变量i和j的改变直接响应到主内存中,但在two方法获取到变量i和获取变量j的值的这段时间内,one方法可能会被执行多次,导致j的值大于i. 所以volatile仅保证线程间共享内存的可见性,不能保证并发的有序性.

0 0