目录
synchronized的特性
synchronized的锁机制
synchronized的使用
synchronized的特性
synchronized主要有三大特性:
面试时经常拿synchronized
关键字和volatile
关键字的特性进行对比,synchronized
关键字可以保证并发编程的三大特性:原子性、可见性、有序性,而volatile
关键字只能保证可见性和有序性,不能保证原子性,也称为是轻量级的synchronized
。
- 原子性:一个或多个操作要么全部执行成功,要么全部执行失败。
synchronized
关键字可以保证只有一个线程拿到锁,访问共享资源。 - 可见性:当一个线程对共享变量进行修改后,其他线程可以立刻看到。执行
synchronized
时,会对应执行lock
、unlock
原子操作,保证可见性。 - 有序性:程序的执行顺序会按照代码的先后顺序执行。
synchronized的锁机制
synchronized既是悲观锁,也是乐观锁,既是轻量级锁,也是重量级锁。是可重入锁,不是读写锁,是非公平锁。至于上述名词的意思,可以浏览这篇文章CSDN
synchronized的“自适应”是根据当前锁冲突的概率来调整锁策略。调整的过程分为以下阶段:
偏向锁:首次使用synchronized对对象进行加锁的时候,不是真的加锁。而只是做一个“标记”(非常轻量非常快,几乎没有开销)。如果没有别的线程尝试对这个对象加锁,就可以保持这个暧昧状态,一直到解锁。(解锁也就是修改一下上述标记,也几乎没有开销)上述过程,就相当于没有任何的加锁操作,速度是非常快的,也可以保证锁能够正常生效。但是,如果再偏向锁状态下,有某个线程也尝试来对这个对象加锁,立马把偏向锁升级成轻量级锁(真的有锁,真的有互斥了)。
上述升级过程,针对一个锁对象来说,是不可逆的。一旦升级成了重量级锁,不会退回到轻量级锁。
synchronized的使用
synchronized
主要有三种使用方式:修饰普通同步方法、修饰静态同步方法、修饰同步方法块。
修饰普通同步方法
我们看下列代码:
public class ThreadDemo9 {private static int count;public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1 = new Thread(()->{for (int i = 0; i < 10000; i++) {synchronized (locker){count++;}}});Thread t2 = new Thread(()->{for (int i = 0; i < 10000; i++) {synchronized (locker){count++;}}});t1.start();t2.start();t1.join();t2.join();System.out.println("count = " + count);}
}
运行结果:
这就是使用synchronized保证线程安全,解决内存可见性问题的典型用法。关于内存可见性的详情,可以浏览这篇文章CSDN
修饰静态同步方法
示例代码如下:
class syncTest implements Runnable {private static int i = 0; //共享资源private static synchronized void add() {i++;}@Overridepublic void run() {for (int j = 0; j < 10000; j++) {add();}}public static void main(String[] args) throws Exception {// syncTest syncTest = new syncTest();Thread t1 = new Thread(new syncTest());Thread t2 = new Thread(new syncTest());t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}
运行结果为:
20000
即当synchronized
作用于静态方法add(),锁就是当前的class对象。
修饰同步方法块
如果某些情况下,整个方法体比较大,需要同步的代码只是一小部分,如果直接对整个方法体进行同步,会使得代码性能变差,这时只需要对一小部分代码进行同步即可。代码如下:
class syncTest implements Runnable {static int i = 0; //共享资源@Overridepublic void run() {//其他操作.......synchronized (this){ //this表示当前对象实例,这里还可以使用syncTest.class,表示class对象锁for (int j = 0; j < 10000; j++) {i++;}}}public static void main(String[] args) throws Exception {syncTest syncTest = new syncTest();Thread t1 = new Thread(syncTest);Thread t2 = new Thread(syncTest);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}
输出结果:
20000
以上,关于synchronized希望对你有帮助。