synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized
方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized
方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得
该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized
的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变
量的方法均被声明为 synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized
方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为
synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized
方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized
,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
对synchronized(this)的一些理解(很细致,感谢作者!)
我对synchronized(this)和synchronized(object)的理解:
误区一:synchronized关键字只能用在实现Runnable或者继承了Thread类的子类的方法里面。
正
解:如果有一块代码(或方法)可能被多个线程同时访问,然后里面操作的数据修改操作可能因为不同线程的操作而不一致的时候,使用synchronized
锁定这块代码,确保同时只有一个线程访问这个代码块。也就是说,关键字synchronized可以用在任何类的方法里面,即使该类没有实现
Runnable接口或者继承Thread类。
误区二:synchronized(this)和synchronized(object)作用范围完全不同。
正解:当 多个线程 访问同一个类A 的 方法A()的时候
并且 这个方法A() 要求 一个线程执行完了之后 在给另外一个线程去执行
那么 这个方法A() 9必须加上 synchronized 关键字
或者 在 该方法A()中 写上 synchronized(this//指代当前类A的实例){}
如果不在声明方法A()时 加上synchronized关键字 或者 不在方法A()中加上synchronized(this){}
同步块的时候
可以在 线程类的RUN 方法内
synchronized(Object //指代类A的实例){
Object.A();
}
实现多线程同时有序访问该同步块内类A的方法A()的目的
object本身就包含this的情况。
this指代的是当前同步块所在方法所在的类,当不需要引用别的类的时候。
object指代的是需要调用的类,引用了别的类,且需要处理多线程并发访问时,object指代的是被引用的类。如果没有引用别的类,则指代的就是同步块所在方法所在的类本身。
例:
public class 访问类 { public void A方法() { //synchronized (this) { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " i = " + i); } //} } public void B方法() { //synchronized (this) { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " i = " + i); } //} } }
public class 实例线程类 { public static void main(String[] args) { 访问类 Object = new 访问类(); Thread t1 = new Thread(new 线程A(Object)); Thread t2 = new Thread(new 线程B(Object)); t1.start(); t2.start(); } } class 线程A implements Runnable { private 访问类 object; public 线程A(访问类 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方法(); } } }