线程同步,即对多个线程可能同时访问一个资源的时候。这个时候,有个互斥的要求,一般都是加锁。synchronized。但是,有时候,仅仅这个synchronized是不够用的,还可能会使用到一个不常用的关键字:volatile
下面看看这个简单的多线程同步的代码。看看加不加这个volatile会有什么不同的效果。
package com.lxk.threadTest.mianShiTest.staticAttribute;
/**
* @author lxk on 2017/11/17
*/
public class MyThread implements Runnable {
static Integer i = 0;
@Override
public void run() {
while (true) {
synchronized (i) {
if (i < 100) {
i++;
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " i = " + i);
} else {
break;
}
}
}
}
}
然后就是main方法。
package com.lxk.threadTest.mianShiTest.staticAttribute;
/**
* 首先是2个线程一起执行,再有就是i++他不是原子操作。
*
* @author lxk on 2017/11/17
*/
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
t1.start();
t2.start();
}
}
先是实现多线程同步的代码,直接在main方法里面,new两个线程,启动,就没有然后啦。简单看完之后,有什么想法。可能如下:
2个线程,对静态变量i加锁,说明2个线程加锁的对象是统一的,加锁的是一个东西。保证每次操作的时候,都是线程安全的。。。
所以,猜测的运行结果:
线程0和线程1,两个线程,会输出1-100的数,因CPU执行权的问题,说不好谁先谁后,但是,理论上讲应该是2个线程共同执行,输出1-100。
但是,看下面的实际运行的结果图。
可以看到,1 没有输出,但是2 输出了2次,
对,没错,这个是有随机性的,因为每个人的电脑不同,性能也不同,所以,不一定 会出现这个现象。
但是,我这真出现这个现象啦,这就是线程不安全啦。
正因为这个不确定性,所以,多线程同步的问题,就是个很大的问题。所以,多线程编程,才会那么重要。
因为,这个bug不是你想复现就立马能复现的。
我原以为是给这个静态变量 i 加上 volatile ,问题就算完事了,但是,好像,不是那么回事呐。还是有问题,还是线程不安全。
尴尬啦,
这个问题,暂时没解决呢。
容我先把这个问题留下,但是这个多线程同步的问题,确实厉害,你要是不同步这个 i ++ ,那就不会有这么多事。
2018-01-10,更新如下;
现在找到怎么解决i++不是原子操作的方法啦。
public class MyThread implements Runnable {
private static AtomicInteger i = new AtomicInteger(0);
@Override
public void run() {
while (true) {
synchronized (i) {
if (i.get() < 100) {
//相当于i++
i.getAndIncrement();
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " i = " + i);
} else {
break;
}
}
}
}
}
这个是线程安全的integer。