深入了解Java中Synchronized的各种使用方法

深入了解Java中Synchronized的各种使用方法

在 Java 中,Synchronized 是一种保证多线程访问同一个共享资源时,只有一个线程可以进入代码块,从而保证线程安全的关键字。这篇文章将深入讲解 Java 中 Synchronized 的各种使用方法,例如对象锁、类锁和非阻塞同步等。

对象锁

对象锁是指用 Synchronized 关键字修饰的代码块,将拥有该对象的锁,同一时间只能有一个线程进入该对象的代码块。例如下面这个示例:

class Counter {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public synchronized void decrement() {
        count--;
    }
    public int getCount() {
        return count;
    }
}

在上述示例中,Counter 类中的 increment 和 decrement 方法用了Synchronized 关键字,由此得到了“counter”对象的锁,而 getCount 方法没有使用 Synchronized 关键字,所以多个线程可以同时访问 getCount 方法。

类锁

类锁是指用 Synchronized 关键字修饰的静态方法,将拥有该类的锁,同一时间只能有一个线程进入该类的代码块。例如下面这个示例:

class Counter {
    private static int count = 0;
    public static synchronized void increment() {
        count++;
    }
    public static synchronized void decrement() {
        count--;
    }
    public static int getCount() {
        return count;
    }
}

在上述示例中,Counter 类中的 increment 和 decrement 方法同样用了 Synchronized关键字,但是由于这两个方法是静态方法,所以Synchronized 关键字将获得 Counter 类的锁。

非阻塞同步

非阻塞同步是指用 Synchronized 关键字修饰的代码块中,加锁和解锁都是采用 CAS(Compare And Swap)算法实现的同步方式。例如下面这个示例:

import java.util.concurrent.atomic.AtomicInteger;

class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    public void increment() {
        while (true) {
            int oldCount = count.get();
            int newCount = oldCount + 1;
            if (count.compareAndSet(oldCount, newCount)) {
                break;
            }
        }
    }
    public int getCount() {
        return count.get();
    }
}

在上述示例中,Counter 类中的 increment 方法使用了 AtomicInteger 类来替代基础数据类型,采用了 CAS 算法进行同步,达到了非阻塞同步的目的。这种方法虽然比较复杂,但是可以避免锁竞争和死锁。

示例说明

下面是一个相关示例的解释。

例如,我们有这么一段代码:

public class ThreadSafeExample{
    private String name;

    public ThreadSafeExample(String name){
        this.name = name;
    }

    public synchronized void printString(){
        System.out.println("Begin");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("End");
    }
}

这里,我们有一个线程安全的类 ThreadSafeExample,它有一个同步方法 printString,该方法打印一条字符串并休眠 5 秒钟。

然后,我们再来创建两个类:

public class ThreadA extends Thread {
    private ThreadSafeExample threadSafeExample;
    public ThreadA(ThreadSafeExample threadSafeExample){
        this.threadSafeExample = threadSafeExample;
    }
    public void run(){
        threadSafeExample.printString();
    }
}

public class ThreadB extends Thread {
    private ThreadSafeExample threadSafeExample;
    public ThreadB(ThreadSafeExample threadSafeExample){
        this.threadSafeExample = threadSafeExample;
    }
    public void run(){
        threadSafeExample.printString();
    }
}

ThreadA 和 ThreadB 都是通过接收一个 ThreadSafeExample 类型的参数来初始化的。此外,它们都有一个 run 方法,该方法会调用 printString 方法。

现在,我们来看看如果我们同时启动这两个线程会发生什么:

public class ThreadSafeTest {

    public static void main(String[] args) {
        ThreadSafeExample threadSafeExample = new ThreadSafeExample("ThreadSafe");
        ThreadA threadA = new ThreadA(threadSafeExample);
        ThreadB threadB = new ThreadB(threadSafeExample);
        threadA.start();
        threadB.start();
    }
}

如果你运行上面的代码,你会看到以下输出:

Begin
Begin
End
End

这是因为 printString 方法是同步方法,并且两个线程共享了一个 ThreadSafeExample 实例。因此,它们必须按顺序访问该实例的 synchronized 方法。所以,线程 A 先获取了该实例的锁,然后开始执行 printString 方法。而在等待 5 秒的过程中,线程 B 要等待线程 A 释放该实例的锁,才能获取该实例的锁开始执行 printString 方法。

综上所述,Synchronized 是 Java 中保证线程安全的关键字。通过对不同类型 Synchronized 的使用方法的了解,我们可以更好地实现线程安全的程序。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入了解Java中Synchronized的各种使用方法 - Python技术站

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

相关文章

  • 微信小程序微信登录的实现方法详解(JAVA后台)

    下面是详细的攻略: 背景介绍 微信小程序微信登录是指用户可以通过微信账号快速登录小程序,无需再次注册账号。实现微信登录的关键在于后台服务器实现微信的登录认证功能。本文将详细讲解如何在Java后台实现微信登录的功能。 实现方法 实现微信登录功能的具体步骤如下: 1.前端页面添加微信登录按钮 <button type="primary"…

    Java 2023年5月23日
    00
  • JavaScript编程通过Matlab质心算法定位学习

    JavaScript编程通过Matlab质心算法定位学习攻略 什么是质心算法 质心算法通常用于定位某个区域的中心点,它基于该区域内所有点的加权平均值进行计算。在本攻略中,我们将借助质心算法实现JavaScript编程,通过Matlab计算来定位物体的中心位置。 实现步骤 在网页中,用JavaScript编写函数获取需要计算的物体的坐标数据,并通过Matlab…

    Java 2023年5月19日
    00
  • Java内省实例解析

    Java内省实例解析 什么是Java内省? Java内省是指通过类提供的公共方法来访问类属性和方法的一种机制,用于实现Java Bean自省功能。 如何使用Java内省? Java内省通过Java自带的Introspector类实现。Introspector类提供了丰富的API,用于获取和操作Java Bean中的属性、方法等。 获取Java Bean信息 …

    Java 2023年6月15日
    00
  • Android ListView自定义Adapter实现仿QQ界面

    下面是详细讲解“Android ListView自定义Adapter实现仿QQ界面”的完整攻略。 简介 在Android开发中,ListView是常见的视图控件之一,用来展示一系列的元素。而自定义Adapter可以让我们更加灵活地设置ListView中的每一个Item的布局和内容。本文将介绍如何使用自定义Adapter,实现具有聊天界面中消息气泡特效的QQ界…

    Java 2023年5月23日
    00
  • JDBC连接Access数据库的几种方式介绍

    下面我将为您详细介绍JDBC连接Access数据库的几种方式。 一、JDBC-ODBC桥连接 JDBC-ODBC桥连接是最常见的连接Access数据库的方式,它通过将Java程序中的JDBC调用转换为ODBC调用来实现与Access数据库的连接。 步骤: 在Windows中打开ODBC数据源管理器,添加一个Access数据库数据源。 在Java代码中使用JD…

    Java 2023年6月16日
    00
  • JSP实现在线考试与成绩评测

    确定需求和分析 首先确定在线考试的基本需求,例如考试的种类、时长和考试的试题数量等等。然后根据需求,分析考试的流程和评分方法。 设计数据库 设计一个用于存储考试题目和考生答题情况的数据库。考试题目数据可以包含题目的题目类型、难度等级、答案选项等信息。考生答题情况数据可以包含考生的姓名、考号、所选答案、答题时间等信息。 构建网站环境 在本地计算机硬盘上搭建网站…

    Java 2023年6月15日
    00
  • Java对象深复制与浅复制实例详解

    Java对象深复制与浅复制实例详解 在 Java 中,对象的复制分为浅复制和深复制两种方式。本文将详细讲解 Java 中对象复制的概念、浅复制和深复制的实现方式、以及深浅复制的应用场景。 对象复制的概念 在 Java 中,我们可以通过 new 运算符来生成新的对象实例,但是有时候我们需要创建一个新对象,它的属性和原对象一模一样而且它们内存地址不同,这个时候就…

    Java 2023年5月26日
    00
  • 基于spring boot 2和shiro实现身份验证案例

    实现基于Spring Boot 2和Shiro的身份验证,可以按以下步骤进行: 步骤一:创建Spring Boot项目 使用Spring Initializr或者其他方式创建一个Spring Boot项目。 步骤二:添加Shiro依赖 在项目的pom.xml中添加Shiro的依赖: <dependency> <groupId>org.…

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