欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-12 18:12:47
...

当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步。如果没有同步,就无法保证一个线程所做的修改可以被另外一个线程获知。未能同步共享可变数据会造成程序的活性失败(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();
    }

上一篇: window

下一篇: Struts2.0初步