官方介绍synchronized作用:
同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则用改对象变量的所有读取或写入都是通过同步方法完成的。
一句话来说:
能够保证一段时间内只有一个线程执行该段代码,以达到并发安全的效果,是一种悲观锁。
看2段代码:
public static void main(String[] args) {
for (int i = 0; i <2; i++) {
DoThreads dt = new DoThreads(0);
Thread dothread = new Thread(dt);
dothread.start();
}
}
public class DoThreads implements Runnable {
private static int money;
private static final Object o = new Object();
public DoThreads(int ages) {
super();
this.money = money;
}
@Override
public void run() {
testMethod();
}
public void testMethod(){
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
money=money+10;
}
System.out.println(Thread.currentThread().getName()+"开始"+"===金额"+money);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束"+"===金额"+money);
}
}
输入结果为:
Thread-0开始===金额19870
Thread-1开始===金额19920
Thread-0结束===金额19920
Thread-1结束===金额19920
说明2个线程工作的时候金额发生了串号的错误。我们想要的结果是最后金额20000
这个时候我们的synchronized该上场了~
synchronized有2种用法:
1.对象锁
包括方法锁和同步代码块锁
同步代码块锁:
synchronized(this){
需要同步的代码
}
Object o = new Object();
synchronized(o){
需要同步的代码
}
方法锁:
public synchronized void testMethod(){
}
2.类锁
包括修饰静态方法和锁class对象或静态object对象
修饰静态方法:
public static synchronized void testMethod(){
需要锁代码
}
锁class对象或静态object对象
synchronized (DoThreads.class) {
}
static Object o = new Object();
synchronized(o){
需要同步的代码
}
synchronized有2种用法介绍:
多线程执行同一任务对象,使用对象锁和类锁都能保证线程安全。
多线程执行不同任务对象,使用对象锁不能保证线程安全,使用类锁可以保证线程安全。
synchronize的性质
1 .可重入性
同一个线程的外层方法获得锁之后,内层方法可以直接再次获取该锁
优点 ps:避免死锁 提高封装性
2 .不可中断性
一旦同一个锁被别人获得,只能等待别的线程释放该锁才能获得,如果别人不释放,只能永远等下去。
synchronize缺陷
1.效率低
2.不够灵活
3.无法知道是否成功获得锁
建议使用原则
能用工具包实现就不用synchronize;
能用synchronize实现就用synchronize;
最后再选择lock锁。
使用注意点:
锁对象不能为空,作用域不宜过大,避免死锁