码迷,mamicode.com
首页 > 其他好文 > 详细

synchronized关键字的使用及互斥锁的实现

时间:2019-11-07 19:40:39      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:时间   无效   +=   不同的   读取   代码块   pre   amt   账户   

 

synchronized关键用于多线程环境中实现操作的原子性、互斥性,确保有序的同一时间对同一资源访问。实际上,是锁的一种实现。

用法:

class ClassA{

  synchronized void methodA(){//修饰非静态方法1

//临界区

}

 

synchronized static void methodB(){//修饰静态方法2

//临界区

}

 

void methodC(){

synchronized(){

//修饰代码块3,相较于修饰方法,影响的范围更小

}

}

}

修饰非静态方法时,锁定的对象是当前类的实例,修饰静态方法时,锁定的是当前类。对应于以上的1、2、3即。

synchronized(this) void …

synchronized(ClassA.class) void …

synchronized(this)…

this指的是类的一个实例,所以如果是不同实例,那么锁是无效的,无法做到资源访问的互斥。

因此,尽管在同一个类中都使用了synchronized关键字修饰资源,有时也无法做到安全的访问资源。因为资源对应的锁不是同一个。

多个相关联的资源应该作为同一个资源对应同一把锁。

例如

class ClassA{

  static int val=0;

  synchronized int getVal(){

    return val;

}

synchronized static void addVal(){

  val+=1;

}

}

以上是不安全的,因为两个synchronized所加的锁实际是不同的,不能实现资源访问的互斥。

应当改为:

class ClassA{

  static int val=0;

private final Object valLock=new Object();

  int getVal(){

    synchronized(valLock){

return val;

}

}

static void addVal(){

  synchronized(valLock){

    val+=1;

}

}

}

下面再看一个转账的例子:A账户往B账户转账100,B账户往C账户转账100,每一个账户原始金额为200,线程1负责A到B,线程2负责B到C,由于线程1只对A对象加锁,线程2只对B对象加锁,两者别不互斥,可能导致两个线程读取到B中余额都是200,而最终B中余额是300.

class Account {

  private int balance;

  // 转账

  synchronized void transfer(Account target, int amt){

    if (this.balance > amt) {

      this.balance -= amt;

      target.balance += amt;

    }

  }

}

因此上面的方式不能实现线程操作的安全,应当改为如下

class Account {
  private int balance;
  // 转账
  void transfer(Account target, int amt){
    synchronized(Account.class) {
      if (this.balance > amt) {
        this.balance -= amt;
        target.balance += amt;
      }
    }
  } 
}

对类加锁,这样所有账户对象用同一把锁。

即使如此,可以实现多线程的安全操作,实际上依然是存在问题的。

如果Account类有多个子类AccountSon1 AccountSon2…,那么这些子类既属于自己的类型也同时是Account类型,在调用transfer方法时,上锁的实际是AccountSon1.class AccountSon2.class类型,依然存在安全问题。

那么此时,可以如此

final class Account{

  ……

}

 

 

 

 

 

synchronized关键字的使用及互斥锁的实现

标签:时间   无效   +=   不同的   读取   代码块   pre   amt   账户   

原文地址:https://www.cnblogs.com/perfumeBear/p/11814125.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!