多线程锁 synchronized

1、了解 synchronized

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

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

2、synchronized的特点

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

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

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

3、三种使用方式

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

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

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

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

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、使用代码

public class SyncTest extends Thread {
    private int i=0;
    private String str="obj";

    public void run(){
        synchronized (str){
            while (i<5){
                i++;
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        SyncTest t1=new SyncTest();
        SyncTest t2=new SyncTest();
        t1.start();
        t2.start();
    }
}

结果

Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
Thread-1:1
Thread-1:2
Thread-1:3
Thread-1:4
Thread-1:5

线程-1是等线程-0执行完后才执行的

posted @ 2019-10-21 16:15  hjy1995  阅读(95)  评论(0编辑  收藏  举报