百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

快速掌握Java多线程-线程同步(java多线程并发同步)

citgpt 2024-08-01 13:31 11 浏览 0 评论

目录

快速掌握Java多线程-Thread和Runnable

快速掌握Java多线程-线程同步(java多线程并发同步)

快速掌握Java多线程-构造函数和方法

快速掌握Java多线程-线程同步

快速掌握Java多线程-线程间通信

快速掌握Java多线程-增强功能

在并发编程领域,有效管理多个线程和访问共享资源至关重要。Java 的同步机制使我们能够编排线程交互,确保数据完整性并防止竞争条件。本文将深入探讨线程同步的复杂性。

同步

“synchronized”关键字仅适用于方法和块,不适用于类和变量。当多个线程尝试同时操作时,可能会出现数据不一致问题。为了缓解这个问题,使用了“synchronized”关键字。如果一个方法或块被声明为同步,则在给定对象上一次只允许一个线程执行它,从而解决数据不一致问题。

“synchronized”关键字的主要作用是解决数据不一致问题。但其主要缺点在于增加了线程的等待时间,导致性能问题。因此,除非有特殊要求,否则不建议使用“synchronized”关键字。

当线程想要在给定对象上执行同步方法时,它必须首先获得该对象的锁。一旦线程获得了锁,它就可以在对象上执行任何同步方法。方法执行完成后,线程自动释放锁。锁的获取和释放由 JVM 内部管理,不需要我们手动处理。

当一个线程在给定对象上执行同步方法时,不允许其他线程在同一对象上同时执行任何同步方法。但是,它们可以同时执行非同步方法。

class X {
  synchronized m1()
  synchronized m2()
  m3()
}

如果线程 t1 尝试在对象 x上 执行 m1(),它将获取 x 的锁并开始执行 m1()。这是如果另外一个线程t2尝试执行 m1() 或线程 t3 尝试执行 m2(),则两者都将进入等待状态。但是如果线程 t4 尝试执行 m3(),它将立即执行。

锁的概念基于对象而不是方法。因此,每个 Java 对象都有两个区域:

  1. 非同步区域:该区域可以由任意数量的线程同时访问,例如对象状态保持不变的区域,如 read() 操作中。
  2. 同步区域:该区域一次只能由一个线程访问,特别是在涉及对象的状态发生变化时,比如更新、添加、删除等操作中。

同步示例代码:

class Display {
    public synchronized void wish(String name) {
        for (int i = 0; i < 10; i++) {
            System.out.print("Good Morning:");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            System.out.println(name);
        }
    }
}

class MyThread extends Thread {
    Display d;
    String name;

    MyThread(Display d, String name) {
        this.d = d;
        this.name = name;
    }

    public void run() {
        d.wish(name);
    }
}

class SynchronizedDemo {
    public static void main(String[] args) {
        Display d = new Display();
        MyThread t1 = new MyThread(d, "Dhoni");
        MyThread t2 = new MyThread(d, "Yuvraj");
        t1.start();
        t2.start();
    }
}

此例中,Display类中的wish()方法是同步的,确保一次只有一个线程可以执行它。因此,每个线程(t1和t2)轮流执行wish()方法。

执行结果:

Good Morning:Dhoni
Good Morning:Dhoni
.
.
.
10 times
Good Morning:Yuvraj
Good Morning:Yuvraj
.
.
.
10 times

再看另外一个示例:

Display  d1  =  new  Display (); 
Display  d2  =  new  Display (); 

MyThread  t1  =  new  MyThread (d1, "Dhoni" ); 
MyThread  t2  =  new  MyThread (d2, "Yuvraj" ); 

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

此例中,创建了Display类的两个实例d1和d2。每个实例连同不同的名字分别传递到t1和t2线程中。这些线程负责在各自的Display对象上执行wish()方法。

我们可以看到尽管wish()方法是同步的,但是输出也有可能不连续,因为每个线程都是在不同的 Java 对象上操作(d1d2)的。因此,在这种情况下,同步不能有效地确保正常输出。

所以只有当多个线程操作同一个Java对象时才会同步。如果线程操作不同的Java对象,则不会同步。

此外,Java 中的每个类都拥有一个唯一的锁,称为类级锁。当线程要执行静态同步方法时,它需要获取类级锁。一旦获得,线程就可以执行该类的任何静态同步方法。方法执行完毕后,锁会自动释放。

当一个线程执行静态同步方法时,其他线程不允许同时执行同一类的任何静态同步方法。但是,它们可以同时执行以下方法:

  • static m3()(普通静态方法)
  • synchronized m4()(普通同步方法)
  • m5()(普通方法)

示例代码:

class X {
  static synchronized m1()
  static synchronized m2()
  static m3()
  synchronized m4()
  m5()
}

如果一个线程t1尝试执行m1(),它会获取类级锁 ( CL(X))。如果另一个线程t2尝试执行m1(),它就会进入等待状态。同样,如果t3尝试执行m2(),也会进入等待状态。但是线程t4可以在没有任何争用的情况下执行m3()。同样线程t5可以执行m4()并且线程t6也可以无任何争用地执行m5()。

同步块

当只有几行代码需要同步时,不建议将整个方法声明为同步。相反,这些特定的代码行可以包含在同步块中。与同步方法相比,使用同步块的主要优点是减少线程等待时间,从而提高系统性能。

同步块可以通过以下方式声明:

获取当前对象(this)的锁:

synchronized(this) {
  // Only the thread that acquires the lock of the current object can execute this area
}

获取特定对象的锁:

synchronized(b) {
  // Only the thread that acquires the lock of the object 'b' can execute this area
}

获取类级锁:

synchronized(Display.class) {
  // Only the thread that acquires the class-level lock of the "Display" class can execute this area
}

锁概念

锁概念适用于对象和类类型,但不适用于原生类(也叫基本数据类型)。由于需要引用类型,尝试将基本类型作为参数传递给同步块将导致编译错误。

一个线程可以同时从不同的对象获取锁。例如:

class X {
 public synchronized void m1() {
    // Thread holds lock of 'X' object
 
  Y y = new Y();
  
  synchronized(y) {
    // Thread holds locks of 'X' and 'Y' objects
    
   Z z = new Z();
   synchronized(z) {
      // Thread holds locks of 'X', 'Y', and 'Z' objects
   }
  }
 }
}

X x = new X();
x.m1();

目录

快速掌握Java多线程-Thread和Runnable

快速掌握Java多线程-构造函数和方法

快速掌握Java多线程-线程同步

快速掌握Java多线程-线程间通信

快速掌握Java多线程-增强功能

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: