`

java线程同步synchronized的理解

阅读更多

由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。

  需要明确的几个问题:

  1)synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。

  2)无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。

  3)每个对象只有一个锁(lock)与之相关联。

  4)实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

  1、synchronized关键字的作用域有二种:

  1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;

  2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。

  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。

  在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。

  synchronized 方法的缺陷:同步方法,这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象 P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法.同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(;若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。

  2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象。

  这时锁就是对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:

<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->  class Foo implements Runnable   {   private byte[] lock = new byte[0]; // 特殊的instance变量   Public void methodA()   {   synchronized(lock) { //… }   }   //…..   }

  注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。

  3.将synchronized作用于static 函数,示例代码如下:

 

<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->  Class Foo   {   public synchronized static void methodAAA() // 同步的static 函数   {   //….   }   public void methodBBB()   {   synchronized(Foo.class) // class literal(类名称字面常量)   } }

 

  代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。

  可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。B方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。

  对共享资源的同步访问更加安全的技巧:

  1) 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。

  2)如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。

  补充:

  synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。

分享到:
评论

相关推荐

    java的线程同步机制synchronized关键字的理解_.docx

    Java 线程同步机制中 synchronized 关键字的理解 Java 的线程同步机制是为了解决多个线程共享同一片存储空间所带来的访问冲突问题。其中,synchronized 关键字是 Java 语言中解决这种冲突的重要机制。 ...

    掌握Java线程同步:深入理解与实践

    总结而言,Java线程同步机制包括synchronized关键字、显式锁、等待/通知机制和原子变量等,每种机制都有其特定的使用场景和优势。合理选择和使用这些机制,对于编写高效且正确的多线程Java程序至关重要。

    java 线程同步 信号量控制同步

    Java 中的 synchronized 关键字可以用于实现线程同步。synchronized 关键字可以用来锁定对象或方法,防止多个线程同时访问同一个共享资源。 在 Java 中,还有其他线程同步机制,如volatile 变量、Atomic 变量、Lock...

    java 多线程synchronized互斥锁demo

    "synchronized"关键字就是Java中实现线程同步的关键工具,它用于控制对共享资源的访问,防止出现数据不一致的情况。 标题中的"java 多线程synchronized互斥锁demo"指的是一个示例,展示了如何在多线程环境下使用`...

    java同步synchronized关键字用法示例

    Java中的`synchronized`关键字是多线程编程中的一个重要概念,用于控制并发访问共享资源时的同步机制。在Java中,当多个线程试图同时访问和修改同一块代码或数据时,可能会导致数据不一致的问题。为了解决这个问题,...

    Java多线程同步论文.doc

    在Java中,synchronized关键字是实现线程同步的关键,它提供了互斥访问,保证在任何时刻只有一个线程能够访问共享资源。 1. **synchronized关键字的使用** - **synchronized方法**:当一个方法被声明为...

    Java线程及同步(synchronized)样例代码

    通过具体的代码实现,我们将深入理解Java中的线程同步机制,并学习如何在实际编程中正确地使用这些机制。 #### 二、核心概念与原理 ##### 1. Java线程基础 Java中的线程是程序执行的基本单位,每个线程有自己的...

    java线程同步详解

    总结一下,Java线程同步的关键点: 1. **线程同步是为了解决共享资源的并发访问问题,防止数据不一致和冲突。** 2. **同步意味着线程排队,依次访问共享资源,而不是同时访问。** 3. **只有共享变量(可变状态)才...

    Java多线程同步.pdf

    Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用synchronized关键字还不能...

    线程同步Synchronized,监视器monitor和锁lock的关系2---马克-to-win java视频

    线程同步Synchronized,监视器monitor和锁lock的关系2---马克-to-win java视频

    Java多线程和同步

    Java线程(二):线程同步synchronized和volatile 详细讲解Java 同步的原理技术资料

    Java 线程同步调用

    在深入探讨Java线程同步调用这一主题之前,我们首先需要理解线程同步的基本概念及其在多线程环境中的重要性。线程同步是多线程编程中的一个关键概念,它确保了多个线程在访问共享资源时不会发生冲突,避免了数据不...

    java线程同步及通信

    Java线程同步与通信是多线程编程中的关键概念,用于解决并发访问共享资源时可能出现的数据不一致性和竞态条件问题。以下将详细介绍这两个主题,以及如何通过代码示例进行演示。 1. **线程同步**: 线程同步是确保...

    线程同步Synchronized,监视器monitor和锁lock的关系3---马克-to-win java视频

    线程同步Synchronized,监视器monitor和锁lock的关系2---马克-to-win java视频

    基于Java synchronized同步锁实现线程交互.pdf

    "基于Java synchronized同步锁实现线程交互" Java多线程能够提高CPU利用...因此,在使用Java多线程的场景中,请充分理解Java线程各状态之间的关系及其切换,并使用synchronized、wait()和notify()方法实现线程交互。

    操作系统实验 多线程同步与互斥 java编写 有界面

    操作系统实验是计算机科学教育中的重要组成部分,它...总之,理解和掌握多线程同步与互斥的概念是成为一名合格的Java开发者的关键技能之一。通过实际的编程实验,可以加深对这些概念的理解,并锻炼解决并发问题的能力。

    线程同步Synchronized,监视器monitor和锁lock的关系1---马克-to-win java视频

    线程同步Synchronized,监视器monitor和锁lock的关系1---马克-to-win java视频

    java锁机制Synchronizedjava锁机制Synchronized

    Java 锁机制 Synchronized 是 Java 语言中的一种同步机制,用于解决多线程并发访问共享资源时可能出现的一些问题。 Java 锁机制 Synchronized 的概念 在 Java 中,每个对象都可以被看作是一个大房子,其中有多个...

    详细解读java同步之synchronized解析

    Java中的`synchronized`关键字是实现多线程同步的重要机制,它确保了在并发环境中对共享资源的访问是线程安全的。以下是对`synchronized`的详细解读: ### 1. synchronized的特性 - **互斥性**:当一个线程进入一...

Global site tag (gtag.js) - Google Analytics