线程同步 synchronized

1、了解 synchronized

在Java中,每一个对象都拥有一个锁标记(monitor),也称为监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问,这个锁可通过为方法添加关键字 synchronized 来获得,来保证同一对象在同一

时间只有同一线程在访问,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。

2、synchronized的特点

(1)对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象

(2)使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

(3)通过synchronized无法知道有没有成功获取锁。

3、三种使用方式

(1)修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁

public synchronized void increase(){
  i++;
}

对于当前类的对象加锁,不同对象有不同的锁,针对同一线程访问的加锁;若是两个对象,则两个对象获取不同的锁,两个线程可以同时进入该方法,以上代码的加锁就会出现线程不安全

(2)修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁

扫描二维码关注公众号,回复: 7531292 查看本文章
public static synchronized void increase(){
   i++;
}

作用于静态方法时,其锁就是当前类的class对象锁。由于静态成员不专属于任何一个实例对象,是类成员,即所有该类的对象获取到的都是同一把锁,因此通过class对象锁可以控制静态 成员的并发操作。

(3)修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

修饰代码块有以下三种情况:

  1.对给定对象加锁

public void run() {
        //省略其他耗时操作....
        //使用同步代码块对变量i进行同步操作,锁对象为obj
        synchronized(obj){
            for(int j=0;j<1000000;j++){
                    i++;
              }
        }
    }

该类的不同对象获取到obj的锁是同一把锁,两个线程不能进入该方法,保证线程安全

  2.对当前实例对象 this 加锁

//this,当前实例对象锁
synchronized(this){
    for(int j=0;j<1000000;j++){
        i++;
    }
}

此情况和修饰实例方法的情况相同,有两个线程对象时,会出现线程不安全

  3.对class对象加锁

//class对象锁
synchronized(AccountingSync.class){
    for(int j=0;j<1000000;j++){
        i++;
    }
}

该类的不同对象获取到的class对象锁是同一把锁,两个线程不能进入该方法,保证线程安全

4、使用代码(TODO)

猜你喜欢

转载自www.cnblogs.com/yjh1995/p/11714190.html