synchronized关键字
一、什么时候程序需要锁?
多个线程同时访问某段代码或者某个临界资源进行修改操作时,需要加锁
二、程序为什么需要锁?
eg. 线程A和线程B同时对数字n(默认0)做++操作,
1、线程A读取到数字n为0时,去做++(非原子性)操作,
2、同时线程B读取到数字n为0时,也去做++操作
3、做了两次++操作,最终结果还是1(正确应该是2)。
/**
* @Auther wangdongdong
* @Date 2021/7/21 0021 下午 21:14
* @Description 两个线程同时对数字n=0做1万次++操作
* @Verson 1.0
*/
public class TestNuumPlusBySync {
public class TestNuumPlusBySync implements Runnable{
static TestNuumPlusBySync instance=new TestNuumPlusBySync();
static volatile int n=0;volatile只能保证线程可见性,不能保证线程安全
//加不加synchronized执行结果完全不同
public /*synchronized*/ static void increase(){
n++;
}
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
increase();
}
}
public static void main(String[] args) throws Exception{
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(n);
}
}
不加synchronized执行结果:
197771
加synchronized执行结果:
200000
三、如何使用synchronized?
1、指定加锁对象
2、直接作用于实例方法
3、直接作用于静态方法
//synchronized的几种用法
public class Test_Synchronized {
/*
* 1、指定加锁对象
* 2、直接作用于实例方法
* 3、直接作用于静态方法
*/
private int count =10;
//防止对象印用发生变化,最好对象定义为final
private final Object o=new Object();
//1、指定加锁对象
public void m1(){
synchronized (o){
count--;
System.out.println(Thread.currentThread().getName()+" count="+count);
}
}
//2、直接作用于实例方法
public void m2(){
synchronized (this){ //用this锁定当前对象
count--;
System.out.println(Thread.currentThread().getName()+" count="+count);
}
}
public synchronized void m3(){ //等同于方法2
count--;
System.out.println(Thread.currentThread().getName()+" count="+count);
}
}
//3、直接作用于静态方法
class test_static{
private static int count=20;
public synchronized static void m(){
count--;
System.out.println(Thread.currentThread().getName()+" count="+count);
}
//静态方法没有this对象,方法上使用synchronized,相当于synchronized(T.class)
public static void m_1(){
synchronized(test_static.class){
count--;
System.out.println(Thread.currentThread().getName()+" count="+count);
}
}
}
使用了synchronized就没必要使用volatile,因为synchronized既保证了原子性,也保证了一致性
synchronized遇到异常未处理,默认情况会释放锁,可能导致数据不一致