Java多线程synchronized同步方法详解

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日

相关文章

  • 详解Java如何实现加密或者解密PDF文档

    让我来详细讲解Java如何实现加密或者解密PDF文档的完整攻略。 一、PDF加密或解密的基本原理 在讲解如何实现PDF加密或解密之前,先来了解一下PDF加密或解密的基本原理。 PDF加密是通过对PDF文档进行加密处理,在文档中添加一些限制来保护PDF文档的安全性。PDF加密主要包括以下方式: 对PDF文档全文进行加密,需要输入密码才能查看; 对PDF文档的部…

    Java 2023年5月26日
    00
  • JQuery ztree 异步加载实例讲解

    JQuery ztree 异步加载实例讲解 什么是ztree ztree是基于JQuery封装的一款快速、简洁的前端Javascript树形插件。其具有简单易用、功能强大、兼容性好等特点,在众多的前端树形插件中有着广泛的应用。 ztree异步加载的目的 在处理较大数据集合时,直接获取全部数据即使是在客户端也会产生较大的冗余和访问压力。而ztree的异步加载机…

    Java 2023年6月15日
    00
  • Nett分布式分隔符解码器逻辑源码剖析

    Nett分布式分隔符解码器逻辑源码剖析 什么是Netty分布式分隔符解码器? Netty分布式分隔符解码器是一个可复用的组件,用于将输入流分割成单个的消息。 为什么要使用Netty分布式分隔符解码器? 在TCP等流式协议中,数据是以流的方式传输的,并且没有消息边界的概念。如果需要将输入流分割成单个的消息并进行处理,就需要用到解码器。 Nett分布式分隔符解码…

    Java 2023年5月20日
    00
  • Spring Security 实现多种登录方式(常规方式外的邮件、手机验证码登录)

    Spring Security 实现多种登录方式攻略 Spring Security 作为一个强大的安全框架,支持多种登录方式,包括传统的用户名密码登录、第三方登录、手机短信验证码登录、邮件验证码登录等。本攻略将详细介绍如何使用 Spring Security 实现多种登录方式。 传统的用户名密码登录 传统的用户名密码登录是我们最常见的登录方式,主要涉及以下…

    Java 2023年6月3日
    00
  • java WebSocket 服务端实现代码

    下面是实现Java WebSocket服务端的完整攻略,包括示例说明。 准备工作 在开始编写WebSocket服务端代码之前,需要先确保拥有以下条件: Java开发环境,最好使用JDK8或以上版本。 WebSocket API,Java提供了JSR-356标准的WebSocket API,可以通过Maven添加依赖以使用API。 <dependency…

    Java 2023年5月19日
    00
  • Spring Data JPA注解Entity使用示例详解

    Spring Data JPA注解Entity使用示例详解 本文将详细介绍Spring Data JPA注解Entity的使用方法,包括如何定义实体类、如何使用注解配置实体类以及实现一些基本的CRUD操作。下文将通过两个示例演示Spring Data JPA注解Entity的使用方法。 示例一:定义实体类 定义实体类是Spring Data JPA的第一步,…

    Java 2023年6月2日
    00
  • Java模拟多线程实现抢票代码实例

    以下是关于“Java模拟多线程实现抢票代码实例”的详细攻略: 什么是多线程 多线程是指在同一程序中,多个线程同时运行,实现多个任务同时执行的一种编程方式。在Java中,线程是比进程更小的执行单元,每个线程都可以独立地运行和完成自己的任务。 实现多线程的两种方式 继承Thread类 通过继承Thread类并重写它的run()方法来实现多线程。重写run()方法…

    Java 2023年5月18日
    00
  • springboot使用nacos的示例详解

    Spring Boot 使用 Nacos 的示例详解 在本文中,我们将详细介绍如何在 Spring Boot 中使用 Nacos。我们将介绍 Nacos 的概念、配置和使用,并提供两个示例。 Nacos 概念 Nacos 是一个开源的动态服务发现、配置和服务管理平台。Nacos 可以帮助我们快速搭建微服务架构,并提供了许多开箱即用的功能,如服务注册、配置管理…

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