深入了解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日

相关文章

  • C#调用Java代码的方法介绍

    关于C#调用Java代码,通常可以采用以下两种方式: 1. 使用JNI实现Java和C#之间的互操作 Java 提供了JNI接口来实现Java和本地语言的互操作,C#也能够通过JNI接口调用Java代码,实现Java和C#的互操作。 JNI概述 JNI(Java Native Interface)是一种编程框架,Java 开发者可以使用它来访问不同的本地库,…

    Java 2023年5月26日
    00
  • MyBatis实现表连接查询写法(三种对应关系)的方法总结

    关于“MyBatis实现表连接查询写法(三种对应关系)的方法总结”的完整攻略,我可以提供如下内容: 1. 需求 在实际开发中,经常需要对多个表进行联合查询,通常使用某些条件将多个表的数据关联起来。 2. 联接查询分类 联接查询可分为三种对应关系: 2.1 一对一 一对一映射是指两个表中的一行只能对应另一个表中的一行, 例如 一个学生对应一个身份证,一个身份证…

    Java 2023年5月19日
    00
  • 使用hibernate和struts2实现分页功能的示例

    使用Hibernate和Struts2实现分页功能可以分为以下几个步骤: 添加依赖 在pom.xml文件中添加Hibernate和Struts2的依赖,示例代码如下: <dependencies> <!– Hibernate –> <dependency> <groupId>org.hibernate&lt…

    Java 2023年5月20日
    00
  • 关于Java如何正确地实现方法重载详解

    关于Java如何正确地实现方法重载详解 什么是方法重载? 方法重载(Method Overloading)指的是在一个类中定义多个同名方法,但它们的形式参数列表不同。 方法重载的目的是为了让同名方法能够接收不同类型或者不同数量的参数而有不同的行为,实现更加灵活和通用的功能。 什么条件下才能进行方法重载? 方法名称相同; 参数个数或者类型不同; 方法返回值可以…

    Java 2023年5月19日
    00
  • 基于Spring + Spring MVC + Mybatis 高性能web构建实例详解

    基于Spring + Spring MVC + Mybatis 高性能web构建实例详解 简介 Spring + Spring MVC + Mybatis是一种常用的Java Web开发框架组合,它们分别负责业务逻辑、Web层和数据访问层。本文将介绍如何使用这三个框架构建高性能的Web应用程序。 环境搭建 在开始之前,我们需要先搭建好开发环境。以下是环境搭建…

    Java 2023年5月17日
    00
  • SpringMVC拦截器运行原理及配置详解

    下面我就来详细讲解一下“SpringMVC拦截器运行原理及配置详解”。我们先从原理讲起。 SpringMVC拦截器运行原理 SpringMVC拦截器是一个非常重要的概念,它在SpringMVC框架的基础上进行了一定的封装,可以对请求进行拦截和处理。在SpringMVC中,可以通过实现拦截器接口,来实现自己的拦截器。 SpringMVC拦截器在处理流程中的位置…

    Java 2023年5月16日
    00
  • Java基础–数据结构

    数据结构 Java工具包提供了强大的数据结构。在Java中的数据结构主要包括以下几种接口和类:枚举(Enumeration)、位集合(BitSet)、向量(Vector)、栈(Stack)、字典(Dictionary)、哈希表(Hashtable)、属性(Properties)以上这些类是传统遗留的,在Java2中引入了一种新的框架-集合框架(Collect…

    Java 2023年4月17日
    00
  • Spring Security 过滤器注册脉络梳理

    Spring Security 是 Spring 框架的子项目,专门用于处理认证与授权相关的安全问题。在 Spring Security 的实现过程中,过滤器是一个核心概念,所有认证和授权都是通过过滤器实现的。因此,了解 Spring Security 过滤器的注册脉络对于学习 Spring Security 至关重要。 Spring Security 过滤…

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