原子性提供了程序的互斥操做,同一时刻只能有一个线程能对某块代码进行操做。java
在jdk中,原子性的实现方式主要分为:git
synchronized
:关键词,它依赖于JVM,保证了同一时刻只能有一个线程对做用对象的做用范围内进行操做。Lock
:代码层面的锁,依赖CPU指令,主要实现类ReentrantLock
,以后再说。atomic
包:该包中提供了一些能够保证原子操做的类。注意上面加粗内容,比较关键,后面会有讲解,着重理解多线程
从性能上看,上面三个逐优,但各自又有不一样。函数
synchronized
是不可中断锁,适合竞争不激烈,可读性比较好。Lock
是可中断锁,多样化同步,竞争激烈时能维持常态。atomic
竞争激烈时能维持常态,比Lock性能好,但只能同步一个值。synchronized
修饰的代码块,做用于调用的对象synchronized
修饰的方法,做用于调用的对象synchronized
修饰的静态方法,做用于这个类的全部对象synchronized
修饰的类,做用于这个类的全部对象package cn.com.dotleo.sync; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by liufei on 2018/6/24. */ public class Sync1 { public void test1(int x) { synchronized (this) { for (int i = 0; i < 10; i++) { System.out.println("["+ x + "]test1: " + i); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { final Sync1 sync = new Sync1(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new Runnable() { public void run() { sync.test1(1); } }); executorService.execute(new Runnable() { public void run() { sync.test1(2); } }); } }
代码参见Sync1.java性能
上面代码中,主要体现了多线程下,同一个对象调用同步代码块。this
运行结果:atom
[1]test1: 0 [1]test1: 1 [1]test1: 2 [1]test1: 3 [1]test1: 4 [1]test1: 5 [1]test1: 6 [1]test1: 7 [1]test1: 8 [1]test1: 9 [2]test1: 0 [2]test1: 1 [2]test1: 2 [2]test1: 3 [2]test1: 4 [2]test1: 5 [2]test1: 6 [2]test1: 7 [2]test1: 8 [2]test1: 9
由此结果能够看出,在多线程下,两个线程同时做用于一个对象时,该代码块被先抢到资源的进程执行结束后另外一个线程才得以执行。线程
将主函数修改以下:code
public static void main(String[] args) { final Sync1 sync1 = new Sync1(); final Sync1 syncNew = new Sync1(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new Runnable() { public void run() { sync1.test1(1); } }); executorService.execute(new Runnable() { public void run() { syncNew.test1(2); } }); }
代码参见Sync1.java对象
[1]test1: 0 [2]test1: 0 [1]test1: 1 [2]test1: 1 [1]test1: 2 [2]test1: 2 [1]test1: 3 [2]test1: 3 [1]test1: 4 [2]test1: 4 [1]test1: 5 [2]test1: 5 [1]test1: 6 [2]test1: 6 [1]test1: 7 [2]test1: 7 [1]test1: 8 [2]test1: 8 [2]test1: 9 [1]test1: 9
从结果中能够看出,对于两个线程分别调用两个对象时,并无锁的出现,线程交叉执行并输出。
同理,synchronized
关键词修饰方法也是如此,这里再也不演示,代码参见Sync2.java
所以咱们能够看出:
synchronized
修饰的代码块,做用于调用的对象synchronized
修饰的方法,做用于调用的对象修饰静态方法:
package cn.com.dotleo.sync; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by liufei on 2018/6/24. */ public class Sync3 { public static synchronized void test3(int x) { for (int i = 0; i < 10; i++) { System.out.println("["+ x + "]test3: " + i); } } public static void main(String[] args) { final Sync3 sync3 = new Sync3(); final Sync3 syncNew = new Sync3(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new Runnable() { public void run() { sync3.test3(1); } }); executorService.execute(new Runnable() { public void run() { syncNew.test3(2); } }); } }
代码参见Sync3.java
关于synchronized修饰静态方法和类再也不演示两个线程调用同一个对象,由于那样确定是加锁的顺序输出。
[1]test3: 0 [1]test3: 1 [1]test3: 2 [1]test3: 3 [1]test3: 4 [1]test3: 5 [1]test3: 6 [1]test3: 7 [1]test3: 8 [1]test3: 9 [2]test3: 0 [2]test3: 1 [2]test3: 2 [2]test3: 3 [2]test3: 4 [2]test3: 5 [2]test3: 6 [2]test3: 7 [2]test3: 8 [2]test3: 9
修饰静态类:
package cn.com.dotleo.sync; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by liufei on 2018/6/24. */ public class Sync4 { public static void test4(int x) { synchronized (Sync4.class) { for (int i = 0; i < 10; i++) { System.out.println("["+ x + "]test4: " + i); } } } public static void main(String[] args) { final Sync4 sync4 = new Sync4(); final Sync4 syncNew = new Sync4(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new Runnable() { public void run() { sync4.test4(1); } }); executorService.execute(new Runnable() { public void run() { syncNew.test4(2); } }); } }
代码参见Sync4.java
[1]test4: 0 [1]test4: 1 [1]test4: 2 [1]test4: 3 [1]test4: 4 [1]test4: 5 [1]test4: 6 [1]test4: 7 [1]test4: 8 [1]test4: 9 [2]test4: 0 [2]test4: 1 [2]test4: 2 [2]test4: 3 [2]test4: 4 [2]test4: 5 [2]test4: 6 [2]test4: 7 [2]test4: 8 [2]test4: 9
从上面的两个示例中均可以看出,在两个线程调用一个类的不一样对象时,仍然能保证原子性。
因而可知:
synchronized
修饰的静态方法,做用于这个类的全部对象synchronized
修饰的类,做用于这个类的全部对象特别强调:
synchronized
不是方法申明的一部分,若是子类继承了父类的synchronized
方法,除非子类不会有synchronized
修饰的。