java中同步(synchronized)访问共享的可变数据及原子性操作

当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步。如果没有同步,就无法保证一个线程所做的修改可以被另外一个线程获知。未能同步共享可变数据会造成程序的活性失败(liveness failure)和安全性失败(safety failure)。这样的失败是最难以调试的。它们可能是间歇性的,切与时间相关,程序的行为在不同的VM上可能根本不同。如果只需要线程之间的交互通信,而不需要互斥,volatile修饰符就是一种可以接受的同步形式,但要正确地使用它可能需要一些技巧。

“原子操作(atomic operation)是不需要synchronized”,这是Java多线程编程的老生常谈了。所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切 [1] 换到另一个线程)。

1.1 关键字synchronized

关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法,或者某一个代码块。

如下示例:

package thread;

import java.util.concurrent.TimeUnit;

public class StopThreadSynch {

    private static boolean stopRequested;


    public static synchronized boolean isStopRequested() {
        return stopRequested;
    }


    public static synchronized void setStopRequested(boolean stopRequested) {
        StopThreadSynch.stopRequested = stopRequested;
    }


    public static void main(String[] args) throws InterruptedException {
        long startDate = System.currentTimeMillis();
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                int i = 0;
                while(!isStopRequested()) {
                    i++;
                    System.out.println(i);
                }

            }
        });
        thread.start();

        TimeUnit.SECONDS.sleep(1);

        setStopRequested(true);
        long endDate = System.currentTimeMillis();
        System.out.println(endDate - startDate);
        System.out.println("-----------");
    }
}

注意写方法和读方法都是被同步了,如果只有写方法被同步而读方法没有被同步,同步就不会起作用。

1.2 看如下的例子
    private static int nextNumber = 0;

    public static synchronized int generateNumber() {
        return nextNumber++;
    }

这个方法的目的是要确保每个调用都返回不同的值(只要不超过2的32次方),所以在方法块上加了synchronized同步关键字,这样可以确保多个调用不会交叉存取,确保每个调用都会看到之前所有的调用的效果。

另外一种方法是使用java.util.concurrent.atomic的一部分,这个包下面有我们常用的几个类:
java.util.concurrent.atomic.AtomicBoolean,
java.util.concurrent.atomic.AtomicInteger,
java.util.concurrent.atomic.AtomicIntegerArray,
java.util.concurrent.atomic.AtomicLong,
java.util.concurrent.atomic.AtomicLongArray
它们所做的正是我们想要的,而且有可能比同步版(synchronized)执行的更好:

    private static final AtomicInteger nextNumber = new AtomicInteger();

    public static int generateNumber() {
        return nextNumber.getAndIncrement();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值