学习Java内存模型JMM心得

学习Java内存模型JMM心得

什么是Java内存模型

Java内存模型(Java Memory Model,JMM)是一种用于保证在多线程情况下共享变量的可见性和有序性的机制。

JMM的核心概念

Java内存模型中有三个核心概念:原子性、可见性和有序性。

原子性

原子性指的是在同一时间只有一个线程可以访问共享变量。Java中的基本数据类型,如int、long等,都是具有原子性的。但是,对于复合操作,如i++,实际上是由多个步骤组成的,因此需要通过synchronized或者java.util.concurrent.locks中的锁机制来保证原子性。

可见性

可见性指的是一个线程对共享变量的修改,能够被其他线程及时地看到。在Java中,可以使用volatile关键字来保证可见性。通过volatile关键字,对该变量进行读操作时会直接从内存中读取最新的值,对该变量进行写操作时会立即将修改的值刷回到内存中。

有序性

有序性指的是指令执行的顺序,Java中通过happens-before的规则来保证有序性。happens-before的规则规定了一些时间上的先后顺序,例如在一个线程中,先发生的指令会先执行;在一个锁里,先释放锁的线程的操作happens-before于后获取锁的线程中的操作。

JMM的示例说明

示例1:通过volatile关键字保证变量可见性

下面是一段代码,其中共享变量flag未使用volatile关键字修饰:

class MyThread implements Runnable {
    private boolean flag = false;

    public void run() {
        while (!flag) {
            //Do something
        }
        System.out.println("Thread stopped.");
    }

    public void stop() {
        this.flag = true;
    }
}

public class VolatileTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread t = new Thread(myThread);
        t.start();
        Thread.sleep(1000);
        myThread.stop();
    }
}

在上面代码中,flag被一个线程修改后,另一个线程无法及时地感知到其变化。因此,程序无法正常停止。现在我们通过将flag变量使用volatile关键字修饰,使其变为可见的。

class MyThread implements Runnable {
    private volatile boolean flag = false;

    public void run() {
        while (!flag) {
            //Do something
        }
        System.out.println("Thread stopped.");
    }

    public void stop() {
        this.flag = true;
    }
}

public class VolatileTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread t = new Thread(myThread);
        t.start();
        Thread.sleep(1000);
        myThread.stop();
    }
}

示例2:使用锁机制保证原子性

下面是一个简单的例子,使用volatile关键字不足以保证原子性。

class MyRunnable implements Runnable {
    private volatile int count = 0;

    public void run() {
        for (int i = 0; i < 100000; i++) {
            count++;
        }
        System.out.println("count: " + count);
    }
}

public class VolatileAtomicityTest {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread t1 = new Thread(myRunnable);
        Thread t2 = new Thread(myRunnable);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

在上面的代码中,我们使用volatile关键字保证了count变量的可见性,但是由于count++操作是一个复合操作,因此并不具备原子性。运行上面的代码,就会发现输出的count的值并不是预期的200000。现在我们可以使用锁机制来保证原子性。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class MyRunnable implements Runnable {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void run() {
        for (int i = 0; i < 100000; i++) {
            lock.lock();
            try {
                count++;
            } finally {
                lock.unlock();
            }
        }
        System.out.println("count: " + count);
    }
}

public class LockAtomicityTest {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread t1 = new Thread(myRunnable);
        Thread t2 = new Thread(myRunnable);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

在上述代码中,我们使用了Lock机制来保证了count变量的原子性。运行上面的代码,输出的count的值为200000,证明了操作的原子性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:学习Java内存模型JMM心得 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • java中读写Properties属性文件公用方法详解

    Java中读写Properties属性文件公用方法详解 什么是Properties属性文件? Properties属性文件是Java中常用的一种配置文件,使用键值对的形式来保存配置数据。通常我们将应用程序中需要用户自行配置的数据以及程序运行时需要用到的配置数据都存储在Properties属性文件中进行统一管理。这种文件通常采用.properties扩展名。 …

    Java 2023年6月15日
    00
  • Spring Boot 简介(入门篇)

    SpringBoot简介(入门篇) 什么是SpringBoot Spring Boot 是一个用于快速创建 Spring 应用程序的框架。它基于 Spring 框架,遵循“约定优于配置”的原则,提供了很多默认配置,简化了 Spring 应用程序的开发过程。 SpringBoot的优点 快速开发: Spring Boot 可以快速创建独立运行的 Spring …

    Java 2023年5月15日
    00
  • Java程序执行过程及内存机制详解

    下面是“Java程序执行过程及内存机制详解”的完整攻略: Java程序执行过程 编译器将代码转换成字节码 当我们编写Java程序时,使用的是Java语言,而计算机并不能理解Java语言,所以我们需要将Java源代码通过Java编译器(例如javac命令)转换成一种中间形式的代码,叫做字节码(Byte Code),也称为类文件(class file)。这个过程…

    Java 2023年5月23日
    00
  • 如何用Java Stream写出既高雅又装*的代码

    如何用Java Stream写出既高雅又装*的代码? Java Stream可以被用来解决很多问题,从简单的过滤到复杂的组合操作。它极大地减少了编写的代码量,提高了代码的可读性、可维护性和可重用性。 下面是一些使用Java Stream的技巧,可以让你写出高雅又装*的代码。 1. 使用Lambda表达式写过滤器 传统的Java代码需要明确指定每一步操作的细节…

    Java 2023年5月26日
    00
  • Java时区转换及Date类实现原理解析

    Java时区转换及Date类实现原理解析 在Java中涉及到时间日期处理的时候,经常会涉及到时区的转换问题。本文将详细讲解Java中的时区转换方法及Date类的实现原理。 时区转换 概述 时区是地球上按照地理位置划分的区域,每个时区都有一个与协调世界时(UTC)相差的固定时间偏移量。在国际化的应用中,处理时区转换是非常重要的。Java提供了多种方式来处理时区…

    Java 2023年5月20日
    00
  • JDBCTM 指南:入门2 – 连接

    JDBC是Java Database Connectivity的缩写,是Java编程语言的一种应用程序接口,用于规范客户端程序如何访问数据库。在本指南中,我们将介绍使用JDBC连接数据库的基础知识,包括配置JDBC驱动程序、建立数据库连接、执行SQL查询和更新请求等方面的内容。 配置JDBC驱动程序 在使用JDBC访问数据库之前,需要先配置JDBC驱动程序,…

    Java 2023年6月15日
    00
  • java向数据库插入数据显示乱码的几种问题解决

    下面我将详细讲解“java向数据库插入数据显示乱码的几种问题解决”的完整攻略。 问题描述 在使用Java向数据库插入数据时,有时会出现插入的数据显示乱码的情况。这时需要针对性地解决这个问题。 解决方案 Java向数据库插入数据出现乱码的情况,主要是因为字符集不统一导致。下面就来介绍几种解决方式。 1.配置JDBC连接的字符集 在Java程序连接数据库时,可以…

    Java 2023年5月20日
    00
  • Java中的clone方法实例详解

    Java中的clone方法实例详解 什么是clone方法 clone()方法是Object类提供的一个protected方法,实现对象的复制(克隆)。通过调用对象的clone()方法返回一个复制后的对象,对象的类型与原对象的类型相同。 clone方法的实现 Object中的clone方法是原生方法,性能非常高。因此,我们在实现clone方法时要重写clone…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部