资讯专栏INFORMATION COLUMN

Java中的synchronized关键字

lylwyy2016 / 1944人阅读

摘要:的关键字中的块使用关键字进行标记。由于每个类只有一个类对象存在于中,因此全局同时只有一个线程能够进入到同一个类的静态同步方法中。同步代码块使这种期望成为可能。注意同步代码块如何在括号中接受一个对象。相同的实例被传入两个不同的线程实例中。

Java的synchronized块标记一个方法或一个代码块为同步的。synchronized块能用于防止出现竞态条件。

Java的synchronized关键字

java中的synchronized块使用synchronized关键字进行标记。一个synchronized块在某个对象上被同步。所有在某个对象上同步的synchronized块同时只能有一个线程执行,所有其他试图进入synchronized块的线程被阻塞,知道进入synchronized块的线程退出。

synchronized关键字能够用于编辑4种不同类型的块:

实例方法

静态方法

实例方法中的代码块

静态方法中的代码块

这些块被同步在不同的对象上。哪种synchronized块是你需要的取决于实际情况。

同步的实例方法

这里有一个同步的实例方法:

public synchronized void add(int value) {
  this.count += value;
}

注意这里在方法定义中使用synchronized关键字。这告诉Java方法是同步的。

Java中一个同步的实例方法同步在这个方法所在的实例(对象)上。因此,每个实例的同步方法同步在不同的对象上:拥有这个方法的实例。同时只有一个线程能在一个同步的实例方法上执行。如果多于一个实例存在,则一个线程一次能执行在每个实例的一个同步实例方法中,每个实例一个线程。

同步的静态方法

静态方法被标记为synchronized就像实例方法一样使用synchronized关键字。这里有一个同步的静态方法:

public static synchronized void add(int value) {
  count += value;
}

这里synchronized关键字告诉Java这个方法是同步的。

同步的静态方法同步在方法所属的类对象(如MyClass.class)上。由于每个类只有一个类对象存在于JVM中,因此全局同时只有一个线程能够进入到同一个类的静态同步方法中。

如果静态同步方法位于不同的类中,则一个线程能够在每个类的静态同步方法中执行。每个类一个线程。

实例方法的同步代码块

有时不必同步整个方法。有时更倾向于只同步一个方法中的一部分。Java同步代码块使这种期望成为可能。

这里有一个在非同步Java方法中的同步代码块:

public void add(int value) {
  synchronized(this) {
    this.count += value;
  }
}

这个例子使用Java同步代码块使得一块代码可以被同步访问。这块代码现在就好像是一个同步方法被执行。

注意Java同步代码块如何在括号中接受一个对象。在上面的例子中“this”被使用,也就是这个方法调用所在的实例。括号中的对象叫做「monitor object」。这段代码被叫做同步在一个monitor object上。一个同步的实例方法使用它所属的对象作为monitor object。

同时只有一个线程能执行在同步于相同monitor object上的Java代码块。

下面两个例子都是同步在他们被调用的实例上,两者等价:

public class MyClass {
  public synchronized void log1(String msg1, String msg2) {
    log.writeln(msg1);
    log.writeln(msg2);
  }

  public void log2(String msg1, String msg2) {
    synchronized(this) {
      log.writeln(msg1);
      log.writeln(msg2);
    }
  }
}

同时只有一个线程能够执行在上面两个同步代码块之一上面。

可能会有代码块同步在非this对象上。

静态方法中的同步代码块

这些方法同步在方法所属类的类对象上:

public class MyClass {
  public static synchronized void log1(String msg1, String msg2) {
    log.writeln(msg1);
    log.writeln(msg2);
  }

  public static void log2(String msg1, String msg2) {
    synchronized(MyClass.class) {
      log.writeln(msg1);
      log.writeln(msg2);
    }
  }
}

可能会有代码块同步在非MyClass.class上。

synchronized例子

这里有一个例子,启动2个线程,每个线程都在同一个Counter对象上调用add方法。同时只有一个线程会调用同一个对象的add方法,因为这个方法被synchronized关键字修饰在它所属的同一个实例上。

public class Counter {
  
  long count = 0;

  public synchronized void add(long value) {
    this.count += value
  }
}
public class CounterThread extends Thread {

  protected Counter counter = null;

  public CounterThread(Counter counter) {
    this.counter = counter;
  }

  public void run() {
    for(int i = 0; i < 10; i++) {
      counter.add(i);
    }
  }
}
public class Example {

  public static void main(String[] args) {
    Counter counter = new Counter();
    Thread threadA = new CounterThread(counter);
    Thread threadB = new CounterThread(counter);
    
    threadA.start();
    threadB.start();
  }
}

两个线程被创建。相同的Counter实例被传入两个不同的线程实例中。Counter.add()方法在实例上同步,因为add方法是一个实例方法,并被标记为synchronized。因此同时只有一个线程能调用add()方法。另一个线程会等待第一个线程离开add()方法,然后执行。

如果两个线程引用两个不同的Counter实例,则同时调用add()方法不会有问题。调用是对于不同的对象,因此方法调用也同步在不同的对象上。因此调用不会被阻塞。

public class Example {

  public static void main(String[] args) {
    Counter counterA = new Counter();
    Counter counterB = new Counter();
    Thread threadA = new CounterThread(counterA);
    Thread threadB = new CounterThread(counterB);
    
    threadA.start();
    threadB.start();
  }
}

助理这里的threadA和threadB不再引用同一个counter实例。counterA和counterB的add方法同步在各自所属对象上。调用counterA的add()方法不会紫塞调用在counterB的add()方法。

Java的同步实用工具

synchronized机制是Java的第一个用于同步访问共享在多线程间的同步机制。synchronized机制现在看来不是很先进,这也就是为什么Java5推出了一组同步实用类帮助开发者实现更细粒度的同步控制。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75949.html

相关文章

  • Java多线程学习(二)synchronized键字(1)

    摘要:转载请备注地址多线程学习二将分为两篇文章介绍同步方法另一篇介绍同步语句块。如果两个线程同时操作对象中的实例变量,则会出现非线程安全,解决办法就是在方法前加上关键字即可。 转载请备注地址: https://blog.csdn.net/qq_3433... Java多线程学习(二)将分为两篇文章介绍synchronized同步方法另一篇介绍synchronized同步语句块。系列文章传送门...

    xuxueli 评论0 收藏0
  • Java同步块简介

    摘要:同步块用来避免竞争。实际需要那种同步块视具体情况而定。在非同步的方法中的同步块的例子如下所示示例使用同步块构造器来标记一块代码是同步的。在同步构造器中用括号括起来的对象叫做监视器对象。他们的构造器引用同一个实例。 Java 同步块(synchronized block)用来标记方法或者代码块是同步的。Java同步块用来避免竞争。本文介绍以下内容: Java同步关键字(synchro...

    warnerwu 评论0 收藏0
  • Java 中的 Monitor 机制

    摘要:基本元素机制需要几个元素来配合,分别是临界区对象及锁条件变量以及定义在对象上的,操作。这个外部条件在机制中称为条件变量。提供的机制,其实是,等元素合作形成的,甚至说外部的条件变量也是个组成部分。 monitor的概念 管程,英文是 Monitor,也常被翻译为监视器,monitor 不管是翻译为管程还是监视器,都是比较晦涩的,通过翻译后的中文,并无法对 monitor 达到一个直观的描...

    Jacendfeng 评论0 收藏0
  • Java多线程学习(二)synchronized键字(2)

    摘要:关键字加到非静态方法上持有的是对象锁。线程和线程持有的锁不一样,所以和运行同步,但是和运行不同步。所以尽量不要使用而使用参考多线程编程核心技术并发编程的艺术如果你觉得博主的文章不错,欢迎转发点赞。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) J...

    Batkid 评论0 收藏0
  • Java 多线程核心技术梳理(附源码)

    摘要:本文对多线程基础知识进行梳理,主要包括多线程的基本使用,对象及变量的并发访问,线程间通信,的使用,定时器,单例模式,以及线程状态与线程组。源码采用构建,多线程这部分源码位于模块中。通知可能等待该对象的对象锁的其他线程。 本文对多线程基础知识进行梳理,主要包括多线程的基本使用,对象及变量的并发访问,线程间通信,lock的使用,定时器,单例模式,以及线程状态与线程组。 写在前面 花了一周时...

    Winer 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<