前情回顾:i++操作并不是原子操作,因此多线程下会达不到预期的效果,需要通过加锁或AtomicInteger或LongAdder等方法来实现。
i++可以分为三步
我们通过实验来观察实现i++操作的方式。
下面实验中通过继承Thread实现了多线程
错误方法:
1.多线程下直接进行自增操作
public class byte1 extends Thread{
static int a = 0;
@Override
public 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 block
e.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;
@Override
public 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 block
e.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;
@Override
public 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 block
e.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);
@Override
public 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 block
e.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();
@Override
public 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 block
e.printStackTrace();
}
}
System.out.println(a);
long nowTimeMillis1=System.currentTimeMillis();
System.out.println(nowTimeMillis1-nowTimeMillis+"ms");
}
}
运行结果: