前情回顾:i++操作并不是原子操作,因此多线程下会达不到预期的效果,需要通过加锁或AtomicInteger或LongAdder等方法来实现。
i++可以分为三步
我们通过实验来观察实现i++操作的方式。
下面实验中通过继承Thread实现了多线程
错误方法:
1.多线程下直接进行自增操作
public class byte1 extends Thread{static int a = 0;@Overridepublic void run() {for(int i=1;i<=10000;i++) {a++;}}public static void main(String[] args) {long nowTimeMillis=System.currentTimeMillis(); byte1 tByte1 = new byte1();List<Thread> threads = new ArrayList<Thread>();for(int i=1;i<=10;i++) {threads.add(new Thread(tByte1));}for(Thread thread :threads) {thread.start();}for(Thread thread :threads) {try {thread.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(a);long nowTimeMillis1=System.currentTimeMillis();System.out.println(nowTimeMillis1-nowTimeMillis+"ms");}
}
运行结果:
可以看出,与预期的100000差别很大。
2.通过 volatile来实现
public class byte1 extends Thread{volatile static int a = 0;@Overridepublic void run() {for(int i=1;i<=10000;i++) {a++;}}public static void main(String[] args) {long nowTimeMillis=System.currentTimeMillis(); byte1 tByte1 = new byte1();List<Thread> threads = new ArrayList<Thread>();for(int i=1;i<=10;i++) {threads.add(new Thread(tByte1));}for(Thread thread :threads) {thread.start();}for(Thread thread :threads) {try {thread.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(a);long nowTimeMillis1=System.currentTimeMillis();System.out.println(nowTimeMillis1-nowTimeMillis+"ms");}
}
运行结果:
volatile也无法达到预期效果,因为volatile只可以实现可见性以及禁止指令重排。
当a为1时,线程1与线程2都取出a,线程1实现了a++的操作但并未将值写入内存(为写入内存时其他线程看不到),此时线程2也开始执行a++的操作,线程1开始把a=2写入内存,线程2开始把a=2写入内存,
两个线程执行完之后a的值为2。
正确的实现方式:
1.加锁synchronized
加锁的几种方式:
对当前对象加锁,对这个类加锁,对这个方法加锁,对一个对象加锁(但不能是int等基础类型)
synchronized(this){do();
}synchronized(T.class){do();
}synchronized m(){do();
}Object o = new Object();
synchronized(o){do();
}
public class byte1 extends Thread{static int a = 0;@Overridepublic void run() {synchronized (this) {for(int i=1;i<=10000;i++) {a++;}}}public static void main(String[] args) {long nowTimeMillis=System.currentTimeMillis(); byte1 tByte1 = new byte1();List<Thread> threads = new ArrayList<Thread>();for(int i=1;i<=10;i++) {threads.add(new Thread(tByte1));}for(Thread thread :threads) {thread.start();}for(Thread thread :threads) {try {thread.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(a);long nowTimeMillis1=System.currentTimeMillis();System.out.println(nowTimeMillis1-nowTimeMillis+"ms");}
}
运行结果:
2. 通过AtomicInteger实现
public class byte1 extends Thread{//static int a = 0;static AtomicInteger a = new AtomicInteger(0);@Overridepublic void run() {synchronized (this) {for(int i=1;i<=10000;i++) {a.incrementAndGet();}}}public static void main(String[] args) {long nowTimeMillis=System.currentTimeMillis(); byte1 tByte1 = new byte1();List<Thread> threads = new ArrayList<Thread>();for(int i=1;i<=10;i++) {threads.add(new Thread(tByte1));}for(Thread thread :threads) {thread.start();}for(Thread thread :threads) {try {thread.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(a.get());long nowTimeMillis1=System.currentTimeMillis();System.out.println(nowTimeMillis1-nowTimeMillis+"ms");}
}
运行结果:
3.LongAdder实现
public class byte1 extends Thread{//static int a = 0;static LongAdder a = new LongAdder();@Overridepublic void run() {for(int i=1;i<=10000;i++) {a.increment();}}public static void main(String[] args) {long nowTimeMillis=System.currentTimeMillis(); byte1 tByte1 = new byte1();List<Thread> threads = new ArrayList<Thread>();for(int i=1;i<=10;i++) {threads.add(new Thread(tByte1));}for(Thread thread :threads) {thread.start();}for(Thread thread :threads) {try {thread.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(a);long nowTimeMillis1=System.currentTimeMillis();System.out.println(nowTimeMillis1-nowTimeMillis+"ms");}
}
运行结果: