Java多线程synchronized同步方法详解

yizhihongxing

Java多线程synchronized同步方法详解

在Java多线程编程中,保证线程安全是一个必须面对的问题。synchronized是Java中最常用的线程同步机制之一,可以帮助我们对代码进行加锁,防止多个线程同时执行同一段代码,从而保证数据一致性。本篇攻略将详细讲解synchronized同步方法的使用方法。

什么是synchronized

synchronized是Java中的一个关键字,可以用于修饰方法或代码块,使得并发访问共享资源时保证同步。在Java中,每个对象都有一个监视器锁(也叫内部锁或对象锁),并且只有拥有这个锁的线程才能执行该对象中的synchronized方法或代码块。

synchronized方法的定义

synchronized方法是一种加锁机制,可以防止其他线程同时进入该方法,保证方法的原子性。通常来说,synchronized方法的定义方式为:

public synchronized void method() {}

这种方式将整个方法加锁,保证了方法体内的操作是互斥的,同一时间只有一个线程可以执行该方法,避免了多线程并发访问的问题。

此外,synchronized方法还可以用来修饰静态方法,其定义方式为:

public static synchronized void staticMethod() {}

synchronized方法的示例

下面通过两个示例来帮助理解synchronized方法的使用:

示例1:两个线程修改同一变量

假设有一个计数器类Counter,其中包含一个count变量和一个increment()方法,可以将count加1。现在有两个线程同时执行increment()方法,我们需要保证count这个共享变量数据一致。

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
        System.out.println(Thread.currentThread().getName() + ": " + count);
    }
}

在这个示例中,我们定义了一个increment()方法,并用synchronized修饰,保证了对count++这种操作时的原子性,防止了多线程同时对count进行修改的问题。

我们再来定义两个线程T1和T2,同时执行Counter的increment方法:

public class Test {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                counter.increment();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "T1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                counter.increment();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "T2");

        t1.start();
        t2.start();
    }
}

最终的结果将依次输出T1和T2各自增加的count,交替输出:

T1: 1
T2: 2
T1: 3
T2: 4
T1: 5
T2: 6
T1: 7
T2: 8
T1: 9
T2: 10
T1: 11
T2: 12
T1: 13
T2: 14
T1: 15
T2: 16
T1: 17
T2: 18
T1: 19
T2: 20

可以看到,通过synchronized方法,我们成功地保证了count这个共享变量的数据一致性。

示例2:两个线程访问同一对象的两个不同synchronized方法

现在有一个Person类,其中包含一个账户balance变量和一个deposit方法和一个withdraw方法,分别用来向账户中存入和取出金额:

public class Person {
    private int balance;

    public synchronized void deposit(int money) {
        balance += money;
        System.out.println(Thread.currentThread().getName() + " 存入 " + money + ",当前余额为:" + balance);
    }

    public synchronized void withdraw(int money) {
        balance -= money;
        System.out.println(Thread.currentThread().getName() + " 取出 " + money + ",当前余额为:" + balance);
    }
}

在这个示例中,我们将deposit()和withdraw()方法都用synchronized修饰,保证了对balance这个共享变量的访问是互斥的,从而避免了多线程并发访问的问题。

接下来,我们定义两个线程T1和T2,其中T1执行deposit()方法并存入100元,T2执行withdraw()方法并取出50元:

public class Test {
    public static void main(String[] args) {
        Person person = new Person();

        Thread t1 = new Thread(() -> {
            person.deposit(100);
        }, "T1");

        Thread t2 = new Thread(() -> {
            person.withdraw(50);
        }, "T2");

        t1.start();
        t2.start();
    }
}

最终的输出结果为:

T1 存入 100,当前余额为:100
T2 取出 50,当前余额为:50

通过以上示例,我们成功地实现了对共享变量的同步访问,保证多线程并发访问时数据的正确性。

总结

synchronized方法是一种常用的线程同步机制,用来修饰方法或代码块,保证多线程并发访问时共享资源的正确性。在Java中,每个对象都有一个监视器锁(也叫内部锁或对象锁),并且只有拥有这个锁的线程才能执行该对象中的synchronized方法或代码块。

除了synchronized方法,还有其他的线程同步机制,如synchronized代码块、Lock等,开发者可以根据实际应用场景选择合适的线程同步方案。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程synchronized同步方法详解 - Python技术站

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

相关文章

  • springboot 1.5.2 集成kafka的简单例子

    首先我们需要明确,使用Spring Boot集成Kafka主要需要以下几个步骤: 导入kafka相关的依赖 配置Kafka连接参数 实现生产者和消费者 下面我们来一步一步进行操作。 导入kafka相关的依赖 在Spring Boot项目中,我们可以使用Maven或Gradle来管理依赖。在这里我们选择使用Maven,我们在项目的pom.xml文件中加入以下依…

    Java 2023年5月20日
    00
  • 在Ubuntu20.04 LTS中配置Java开发环境

    下面我来为你讲解如何在Ubuntu20.04 LTS中配置Java开发环境。 1. 安装Java 首先需要安装OpenJDK或Oracle JDK,建议使用OpenJDK。 在终端中输入以下命令进行安装: sudo apt update sudo apt install default-jdk 安装完成后,查看Java版本: java -version 如果…

    Java 2023年5月26日
    00
  • 详解Java中-classpath和路径的使用

    详解Java中-classpath和路径的使用 在Java开发中,我们经常会用到classpath和路径,本篇攻略将详细讲解这两个概念的使用方法,以及它们之间的关系。 classpath的作用 classpath是Java虚拟机(JVM)在搜索class文件时所使用的路径,它可以设置为环境变量,也可以在运行时指定。 设置classpath的环境变量 在Win…

    Java 2023年5月26日
    00
  • 微信+angularJS的SPA应用中用router进行页面跳转,jssdk校验失败问题解决

    针对这个问题,我先介绍一下微信JS-SDK和AngularJS的SPA应用中使用router进行页面跳转的基本概念,然后再讲解如何解决jssdk校验失败问题,最后给出两个示例说明。 微信JS-SDK 微信JS-SDK是一套用于支持公众号网页开发的JavaScript程序,提供了丰富的接口和能力,通过这些接口和能力可以实现例如获取用户信息、分享、支付等功能。开…

    Java 2023年6月15日
    00
  • shiro会话管理示例代码

    Shiro 是一个非常流行的 Java 安全框架,在 web 开发中用于管理用户权限、会话管理等功能。对于 Shiro 的会话管理功能,我们可以通过在项目中使用 Shiro 自带的 Session Management 模块来实现,下面是 Shiro 会话管理示例代码的完整攻略。 一、Shiro 会话管理基础 Shiro 会话管理的基础是 Session 接…

    Java 2023年6月15日
    00
  • java实现学生信息录入界面

    下面是“java实现学生信息录入界面”的完整攻略。 步骤一:创建GUI界面 Java的GUI界面可以使用Swing或JavaFX实现。这里我们以Swing为例。 示例一 以下代码展示了如何使用Swing创建一个简单的GUI界面,包含一个文本框和一个按钮: import javax.swing.*; public class StudentInfoGUI ex…

    Java 2023年5月24日
    00
  • centos7.2.1511安装jdk1.8.0_151及mysql5.6.38的方法

    下面给出详细的攻略: 安装JDK1.8.0_151 下载JDK1.8.0_151安装包 从Oracle官网下载对应版本的JDK1.8.0_151压缩包,下载链接为 [jdk-8u151-linux-x64.tar.gz][1]。 解压JDK1.8.0_151安装包 使用以下命令将JDK1.8.0_151解压到 /usr/local/ 目录下: tar -zx…

    Java 2023年5月20日
    00
  • PHP模拟登陆163邮箱发邮件及获取通讯录列表的方法

    下面是关于PHP模拟登陆163邮箱并进行发邮件、获取通讯录列表的详细攻略。 步骤一:模拟登陆163邮箱 首先,我们需要进行模拟登陆163邮箱。为了实现这个目标,我们可以采用CURL库来构建HTTP请求,并通过DOMDocument和SimpleXMLElement处理HTML和XML文档。下面是模拟登陆的详细步骤: 1. 准备登陆数据 我们需要准备一个数组来…

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