Java 在哪些情况下Volatile优于锁定?

Java 在哪些情况下Volatile优于锁定?,java,multithreading,Java,Multithreading,其中有一项声明: Java编程语言允许线程访问共享变量()。通常,为了确保共享变量得到一致可靠的更新,线程应该通过获取锁来确保它独占使用这些变量,按照惯例,锁会强制这些共享变量互斥 Java编程语言提供了第二种机制,volatile字段,在某些方面比锁定更方便 我想弄清楚在哪些方面使用volatile比锁定更方便 我试图弄清楚使用volatile在哪些方面比锁定更方便 在简单的情况下,如果volatile是需要同步的唯一状态,并且操作本质上是原子的,那么它是一种更方便的解决方案 例如: publ

其中有一项声明:

Java编程语言允许线程访问共享变量()。通常,为了确保共享变量得到一致可靠的更新,线程应该通过获取锁来确保它独占使用这些变量,按照惯例,锁会强制这些共享变量互斥

Java编程语言提供了第二种机制,volatile字段,在某些方面比锁定更方便

我想弄清楚在哪些方面使用volatile比锁定更方便

我试图弄清楚使用volatile在哪些方面比锁定更方便

在简单的情况下,如果volatile是需要同步的唯一状态,并且操作本质上是原子的,那么它是一种更方便的解决方案

例如:

public class Processor extends Thread {
    private volatile stopped;

    public void run() {
        while (!stopped) {
            // do stuff
        }
    }

    public void stop() {
        stopped = true;
    }
}

public class Test {
    public static void main(String[] args) {
        Processor p = new Processor();
        p.start();
        Thread.sleep(1000);
        p.stop();
    }
}
public class Counter {
    private volatile int counter;

    public void increment() {
        counter = counter + 1;
    }

    private int get() {
        return counter;
    }
}
如果对
stopped
使用正则变量,则在读写时需要使用
synchronized
(或其他形式或锁定)。。。这是更多的代码和不太方便

 public class Processor extends Thread {
    private stopped;

    public void run() {
        while (!isStopped()) {
            // do stuff
        }
    }

    public synchronized void stop() {
        stopped = true;
    }

    private synchronized boolean isStopped() {
        return stopped;
    }
}
但是,在简单的情况下,这只能作为锁定的替代方案。如果受保护状态需要的不仅仅是原子读取和原子写入,那么它将无法工作。例如:

public class Processor extends Thread {
    private volatile stopped;

    public void run() {
        while (!stopped) {
            // do stuff
        }
    }

    public void stop() {
        stopped = true;
    }
}

public class Test {
    public static void main(String[] args) {
        Processor p = new Processor();
        p.start();
        Thread.sleep(1000);
        p.stop();
    }
}
public class Counter {
    private volatile int counter;

    public void increment() {
        counter = counter + 1;
    }

    private int get() {
        return counter;
    }
}
由于
increment()
的实现方式,上述操作不是线程安全的。为了获得正确的(线程安全的)行为,
increment=increment+1
需要以原子方式完成。易变的不提供这种保证。内存
读取
写入
操作是单独的原子操作,但它们不是作为序列的原子操作

另外,仅仅使用
volatile
变量并没有线程安全的方法来实现
计数器。您需要锁或原子整数(通常依赖于CAS硬件支持…)


1-如果只计算代码行数,则更方便。如果您还考虑到代码作者和维护人员在推理解决方案是正确的方面所做的工作,那么我认为“方便性”在很大程度上是一种幻觉


在哪些情况下Volatile优于锁定

这是一个更难的问题,因为“更好”是一个充满负担的术语。但是,如果您的意思是“性能更高”,那么
volatile
通常在它工作的情况下会更好:

  • 易失性
    读取或写入只会导致内存障碍
  • 锁定操作通常使用CAS指令和一些代码来处理争用。CAS引入了一个内存屏障
  • 原子
    类型通常也通过CAS实现
这个分析有点粗糙,但最基本的是,如果
volatile
能够很好地完成这项工作,那么它可能比其他方法更有效。但有两个警告:

  • 大多数涉及线程间通信或同步的操作对于
    volatile
  • 在正常情况下,
    volatile
    的性能优势太小而不明显。如果存在争用或同步瓶颈,则会发生更改
我试图弄清楚使用volatile在哪些方面比锁定更方便

在简单的情况下,如果volatile是需要同步的唯一状态,并且操作本质上是原子的,那么它是一种更方便的解决方案

例如:

public class Processor extends Thread {
    private volatile stopped;

    public void run() {
        while (!stopped) {
            // do stuff
        }
    }

    public void stop() {
        stopped = true;
    }
}

public class Test {
    public static void main(String[] args) {
        Processor p = new Processor();
        p.start();
        Thread.sleep(1000);
        p.stop();
    }
}
public class Counter {
    private volatile int counter;

    public void increment() {
        counter = counter + 1;
    }

    private int get() {
        return counter;
    }
}
如果对
stopped
使用正则变量,则在读写时需要使用
synchronized
(或其他形式或锁定)。。。这是更多的代码和不太方便

 public class Processor extends Thread {
    private stopped;

    public void run() {
        while (!isStopped()) {
            // do stuff
        }
    }

    public synchronized void stop() {
        stopped = true;
    }

    private synchronized boolean isStopped() {
        return stopped;
    }
}
但是,在简单的情况下,这只能作为锁定的替代方案。如果受保护状态需要的不仅仅是原子读取和原子写入,那么它将无法工作。例如:

public class Processor extends Thread {
    private volatile stopped;

    public void run() {
        while (!stopped) {
            // do stuff
        }
    }

    public void stop() {
        stopped = true;
    }
}

public class Test {
    public static void main(String[] args) {
        Processor p = new Processor();
        p.start();
        Thread.sleep(1000);
        p.stop();
    }
}
public class Counter {
    private volatile int counter;

    public void increment() {
        counter = counter + 1;
    }

    private int get() {
        return counter;
    }
}
由于
increment()
的实现方式,上述操作不是线程安全的。为了获得正确的(线程安全的)行为,
increment=increment+1
需要以原子方式完成。易变的
不提供这种保证。内存
读取
写入
操作是单独的原子操作,但它们不是作为序列的原子操作

另外,仅仅使用
volatile
变量并没有线程安全的方法来实现
计数器。您需要锁或原子整数(通常依赖于CAS硬件支持…)


1-如果只计算代码行数,则更方便。如果您还考虑到代码作者和维护人员在推理解决方案是正确的方面所做的工作,那么我认为“方便性”在很大程度上是一种幻觉


在哪些情况下Volatile优于锁定

这是一个更难的问题,因为“更好”是一个充满负担的术语。但是,如果您的意思是“性能更高”,那么
volatile
通常在它工作的情况下会更好:

  • 易失性
    读取或写入只会导致内存障碍
  • 锁定操作通常使用CAS指令和一些代码来处理争用。CAS引入了一个内存屏障
  • 原子
    类型通常也通过CAS实现
这个分析有点粗糙,但最基本的是,如果
volatile
能够很好地完成这项工作,那么它可能比其他方法更有效。但有两个警告:

  • 大多数涉及线程间通信或同步的操作对于
    volatile
  • 在正常情况下,
    volatile
    的性能优势太小而不明显。如果存在争用或同步,则会发生更改