synchronized的解析

一、synchronized的作用

        能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。互斥性,可见性。

1、synchronized使用前

public class SynRunnable implements Runnable {
    
    @Override
    public void run() {
            try {
                Log.e("aaa",Thread.currentThread().getName()+"...睡眠前...时间="+System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa",Thread.currentThread().getName()+"...睡眠后...时间="+System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

    }
}
SynRunnable runnable = new SynRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();

运行结果:

Thread-4...睡眠前...时间=1565085002442
Thread-5...睡眠前...时间=1565085002445
Thread-4...睡眠后...时间=1565085005443
Thread-5...睡眠后...时间=1565085005447

结论,两个线程并非顺序执行,而是并发执行。

2、synchronized使用后

public class SynRunnable implements Runnable {

    @Override
    public void run() {
        synchronized(this) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

执行结果:

Thread-4...睡眠前...时间=1565085387805
Thread-4...睡眠后...时间=1565085390806
Thread-5...睡眠前...时间=1565085390807
Thread-5...睡眠后...时间=1565085393808

结论:添加synchronized,顺序执行,不是并发执行

 

二、synchronized分类

对象锁,类的对象可以有多个,每个对象有其独立的对象锁,互不干扰。

类锁,每个类只有一个class对象,所有每个类只有一个类锁。

1、根据修饰对象分类

     修饰代码块

           synchronized(this | object)

           synchronized(.class)

    修饰方法

          修饰非静态方法

          修饰静态方法

 

2、根据获取的锁分类

     获取对象锁

           synchronized(this | object)

           修饰非静态方法

    获取类锁

         synchronized(.class)

         修饰静态方法

二、synchronized的两种用法

1、对象锁

    包括方法锁,(默认锁对象为this当前实例对象)和同步代码块锁(自己指定所对象)

(1)单个synchronized(this)

         看 synchronized的作用模块

(2)单个同步代码块锁,synchronized(object)

public class SynRunnable implements Runnable {

    Object object=new Object();

    @Override
    public void run() {
        synchronized(object) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:顺序执行,非并发

Thread-4...睡眠前...时间=1565085707838
Thread-4...睡眠后...时间=1565085710841
Thread-5...睡眠前...时间=1565085710843
Thread-5...睡眠后...时间=1565085713845

(3)多个synchronized(this)   和多个synchronized(object)一样,如果this代表的对象和object代表的对象不一样,反映的结论也是一样的

public class SynRunnable implements Runnable {

    Object objectA = new Object();
    Object objectB = new Object();

    @Override
    public void run() {
        methodA();
        methodB();
    }

    private void methodA() {
        synchronized (objectA) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...方法a...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...方法a...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void methodB() {
        synchronized (objectB) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...方法b...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...方法b...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

Thread-4...方法a...睡眠前...时间=1565087245228
Thread-4...方法a...睡眠后...时间=1565087248229
Thread-4...方法b...睡眠前...时间=1565087248229
Thread-5...方法a...睡眠前...时间=1565087248229
Thread-5...方法a...睡眠后...时间=1565087251230
Thread-4...方法b...睡眠后...时间=1565087251230
Thread-5...方法b...睡眠前...时间=1565087251230
Thread-5...方法b...睡眠后...时间=1565087254231

可以看出,方法a和方法b加的对象锁不一样,是不影响对方的执行,两者之间可以并行。同一个锁对象的不同方法是串行的,互斥

2、类锁

     指synchronized修饰静态的方法或者指定锁为Class类锁

(1)class类锁

public class SynRunnable implements Runnable {


    @Override
    public void run() {
        methodA();
        methodB();
    }

    private void methodA() {
        synchronized (SynRunnable.class) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...方法a...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...方法a...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void methodB() {
        synchronized (SynRunnable.class) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...方法b...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...方法b...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

Thread-5...方法a...睡眠前...时间=1565087517322
Thread-5...方法a...睡眠后...时间=1565087520323
Thread-5...方法b...睡眠前...时间=1565087520324
Thread-5...方法b...睡眠后...时间=1565087523325
Thread-4...方法a...睡眠前...时间=1565087523326
Thread-4...方法a...睡眠后...时间=1565087526328
Thread-4...方法b...睡眠前...时间=1565087526328
Thread-4...方法b...睡眠后...时间=1565087529331

结论:类锁是串行,互斥

(2)静态方法

public class SynRunnable implements Runnable {


    @Override
    public void run() {
        methodA();
        methodB();
    }

    private void methodA() {
        synchronized (SynRunnable.class) {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...方法a...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...方法a...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static synchronized  void methodB() {
            try {
                Log.e("aaa", Thread.currentThread().getName() + "...方法b...睡眠前...时间=" + System.currentTimeMillis());
                Thread.sleep(3000);
                Log.e("aaa", Thread.currentThread().getName() + "...方法b...睡眠后...时间=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

    }
}

运行结果:

Thread-4...方法a...睡眠前...时间=1565087756890
Thread-4...方法a...睡眠后...时间=1565087759892
Thread-4...方法b...睡眠前...时间=1565087759893
Thread-4...方法b...睡眠后...时间=1565087762895
Thread-5...方法a...睡眠前...时间=1565087762899
Thread-5...方法a...睡眠后...时间=1565087765901
Thread-5...方法b...睡眠前...时间=1565087765901
Thread-5...方法b...睡眠后...时间=1565087768903

结论:静态方法和类锁一样,是串行,互斥。

 

三、synchronized和volatile的区别

1、volatile本质高告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized是锁定当前对象,只有当前线程可以访问变量,其他线程被阻塞。

2、valtaile仅使用在变量上,synchronized则可以使用在变量,方法和类上

3、volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值