Java Synchronized方法和方法块的理解

synchronized 关键字,它包括两种用法:

  • synchronized 方法
  • synchronized 块

synchronized 方法

通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:

public synchronized void accessVal(int newVal);

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

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

synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块

synchronized 块

通过 synchronized关键字来声明synchronized 块。语法如下:

synchronized(syncObject) {
	//允许访问控制的代码
}

synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。

常见误区

误区一

synchronized关键字只能用在实现Runnable或者继承了Thread类的子类的方法里面。

正解:如果有一块代码(或方法)可能被多个线程同时访问,然后里面操作的数据修改操作可能因为不同线程的操作而不一致的时候,使用synchronized锁定这块代码,确保同时只有一个线程访问这个代码块。也就是说,关键字synchronized可以用在任何类的方法里面,即使该类没有实现Runnable接口或者继承Thread类。

误区二

synchronized(this)和synchronized(object)作用范围完全不同。

正解:当多个线程访问同一个类A 的 方法A()的时候,项目要求这个方法A() 要在一个线程执行完了之后,再给另外一个线程去执行。那么, 这个方法A()必须加上 synchronized 关键字。或者 ,在该方法A()中写上

synchronized(this)//指代当前类A的实例){}

如果不在声明方法A()时加上synchronized关键字,或者不在方法A()中加上synchronized(this){}同步块的时候,可以在 线程类的RUN 方法内

 //Object 指代类A的实例
synchronized(Object){
	Object.A();
}

实现多线程同时有序访问该同步块内类A的方法A()的目的。

object本身就包含this的情况。

this指代的是当前同步块所在方法所在的类,当不需要引用别的类的时候。object指代的是需要调用的类,引用了别的类,且需要处理多线程并发访问时,object指代的是被引用的类。如果没有引用别的类,则指代的就是同步块所在方法所在的类本身。

public class VistingClass {

 public void Method_A() {
  //synchronized (this) {
   for (int i = 0; i < 100; i++) {
		System.out.println(Thread.currentThread().getName() + " i = " + i);
   }
  //}
 }

 public void Method_B() {
  //synchronized (this) {
   for (int i = 0; i < 100; i++) {
		System.out.println(Thread.currentThread().getName() + " i = " + i);
   }
  //}
 }
}
public class InstanceThreadClass {
 public static void main(String[] args) {
  VisitingClass Object = new 访问VisitingClass ();

  Thread t1 = new Thread(new ThreadA(Object));
  Thread t2 = new Thread(new ThreadB(Object));
  t1.start();
  t2.start();
 }
}

class ThreadA implements Runnable {
 private 访问类 object;

 public ThreadA(访问类 object) {
  // TODO Auto-generated constructor stub
  this.object = object;
 }

 @Override
 public void run() {
  // TODO Auto-generated method stub
  synchronized (object) {
   object.A方法();
  }
 }

}

class 线程B implements Runnable {
 private 访问类 object;

 public 线程B(访问类 object) {
  // TODO Auto-generated constructor stub
  this.object = object;
 }

 @Override
 public void run() {
  // TODO Auto-generated method stub
   synchronized (object) {
   object.B方法();
   }
 }

}

参考

https://blog.csdn.net/xxyyww/article/details/5780806

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值