对实现了
Runnable
或者
Callable
接口类,能够经过多线程执行同一实例的
run
或
call
方法,那么对于同一实例中的局部变量(
非方法变量
)就会有多个线程进行更改或读取,这就会致使数据不一致,
synchronized
(
关键字
)能够解决多线程共享数据同步的问题
synchronized使用说明
做用范围
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有如下几种:
-
修饰一个代码块
:被修饰的代码块称为同步语句块,其做用的范围是大括号{}括起来的代码,做用的对象是调用这个代码块的对象
-
修饰一个非静态方法
:被修饰的方法称为同步方法,其做用的范围是整个方法,做用的对象是调用这个方法的对象
-
修改一个静态的方法
:其做用的范围是整个静态方法,做用的对象是这个类的全部对象
-
修改一个类
:其做用的范围是synchronized后面括号括起来的部分,做用主的对象是这个类的全部对象
高能提示:
No1 >
synchronized修饰的非静态方法:
若是
一个对象
有
多个synchronized方法
,只要
一个线程
访问了其中的
一个synchronized方法
,则这个线程
所属对象
的
其它线程
不能
同时访问
这个
对象
中
任何一个synchronized方法
No2 >
synchronized关键字是不能继承的:
基类的方法
synchronized function(){}
在继承类中并不自动是
synchronized function(){}
,而是变成了
function(){}
。继承类须要你
显式的指定
它的某个方法为
synchronized方法
,能够经过
子类调用父类的同步方法来实现同步
No3 > 针对synchronized修饰代码块和非静态方法,本质上锁的是代码块或非静态方法对应的
对象
(
代码块是synchronized标注的变量,非静态方法是所在类对应的实例
),若是是
不一样的对象
是能够同时访问的
No4 > 实现同步是要很大的
系统开销
做为代价的,甚至可能形成
死锁
,因此尽可能避免
无谓的同步控制
No5 > 每一个对象只有一个锁(lock)与之相关联
No6 > 在定义
接口方法
时不能使用
synchronized
关键字
No7 > 构造方法不能使用
synchronized关键字
,但可使用
synchronized代码块
来进行同步
1. 修饰一个代码块
public void syncCode(Object o) {
synchronized (o) {// 同步代码块}
}
上面的锁就是
o
这个对象,固然多个线程同步须要保证
o
这个对象是
同一个
,这是有明确的对象做为锁的状况,若是只是想单纯的让某一段代码同步,并无明确的对象做为锁,能够建立一个特殊的
instance
变量来充当锁
synchronized(o)
修饰的代码块,其中o
能够取值一个对象
或者一个变量
或者this
亦或者Clz.class
public class Sync implements Runnable {
private byte[] lock = new byte[0];
public void syncCode() {
synchronized (lock) {// 同步代码块}
}
public void run ....
}
注
:
零长度的byte数组
对象建立起来将比任何对象都经济,查看
编译后的字节码
,生成
零长度的byte[]
对象只需3条操做码,而
Object lock = new Object()
则须要7行操做码
2. 修饰一个非静态方法
public synchronized void method() {// .....}
此时锁的是调用这个同步方法的对象
3. 修饰一个静态方法
public synchronized static void method() {// .....}
synchronized修饰的静态方法锁定的是这个类的全部对象
4. 修饰类
public class Sync implements Runnable {
public void syncCode() {
synchronized (Sync.class) {// 同步代码块}
}
public void run ....
}
和做用于静态方法同样,synchronized做用于一个类时,是给这个类加锁,类的全部对象用的是同一把锁
总结
- 线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。
- 线程同步方法是经过锁来实现,每一个对象都有切仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其余访问该对象的线程就没法再访问该对象的其余非同步方法
- 对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程得到锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。
- 对于同步,要时刻清醒在哪一个对象上同步,这是关键。
- 编写线程安全的类,须要时刻注意对多个线程竞争访问资源的逻辑和安全作出正确的判断,对"原子"操做作出分析,并保证原子操做期间别的线程没法访问竞争资源。
- 当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。
- 死锁是线程间相互等待锁锁形成的,在实际中发生的几率很是的小,一旦程序发生死锁,程序将死掉