synchronized关键字属于Java基础的知识范畴,但在Android的framework层源码中,极其常见。
掌握它,是更好的阅读、学习Android源码的前提。
一.基本认知
1.作用
保证同一时刻最多只有1个线程执行 被Synchronized修饰的方法 / 代码。
(即:其他线程 必须等待当前线程执行完该方法 / 代码块后才能执行该方法 / 代码块)
2.应用场景
保证线程安全,解决多线程中的并发同步问题(实现的是阻塞型并发),具体场景如下:
- 修饰 实例方法 / 代码块时,(同步)保护的是同一个对象方法的调用 & 当前实例对象
- 修饰 静态方法 / 代码块时,(同步)保护的是 静态方法的调用 & class 类对象
3.语法
synchronized (obj){
.....
//此处的代码就是同步代码块
}
上述语法格式中synchronized 后括号里的obj就是同步监视器,上述代码的含义是: 线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。
提示:
(1)任何时刻,只能有一个线程可以获得对同步监视器的锁定,但同步代码块执行完成后,该线程会释放对该同步监视器的锁定。
(2)synchronized关键字可以修饰方法,可以修饰代码块,但不能修饰构造器、成员变量等。
二.使用规则
在Java代码中使用synchronized可以使用在代码块和方法中,根据Synchronized用的位置可以有这些使用场景:
如图,synchronized可以用在方法上也可以使用在代码块中,其中方法是实例方法和静态方法分别锁的是该类的实例对象和该类的对象。而使用在代码块中也可以分为三种,具体的可以看上面的表格。这里的需要注意的是:如果锁的是类对象的话,尽管new多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系。
在Java中,虽然程序允许使用任何对象作为同步监视器,但想一下同步监视器的目的: 阻止两个线程对同一个共享资源进行并发访问,因为通常推荐使用可能被并发访问的共享资源充当同步监视器。
三.性能提示:
可变类的线程安全是以降低程序的运行效率作为代价的,为了减少线程安全所带来的负面影响,程序可以采取如下策略:
(1) 不要对线程安全类的所有方法都进行同步,只对那些会改变竞争资源(竞争资源也就是共享资源)的方法进行同步。
(2)如果可变类有两种运行环境: 单线程环境和多线程环境,则应该为该可变类提供两种版本,即线程不安全版本和线程安全版本.在单线程环境中使用线程不安全版本以保证性能,在多线程环境中使用线程安全版本。
JDK所提供的StringBuilder、StringBuffer就是为了照顾单线程和多线程环境所提供的类,在单线程环境下应该使用StringBuilder来保证较好的性能;当需要保证多线程安全时,就应该使用StringBuffer。