您的位置:首页 > 编程语言 > Java开发

java多线程访问同一变量及简单同步问题(待后续整理)

2015-06-26 16:09 323 查看
先贴代码:

import java.util.Vector;

public class Counter {

public static int count = 0;
// synchronized
public static void inc() {
for (int i = 0; i < 1000; i++){
count++;
}
System.out.println(Thread.currentThread().getName() + "----" + count);
}

public static void main(String[] args) {
Vector<Thread> ts = new Vector<Thread>();
for (int i = 0; i < 200; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
}
});
ts.add(t);
t.start();
}
for (Thread t : ts) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

System.out.println("----------" + Counter.count);
}
}

很简单的逻辑,就是for循环开新的线程然后每个线程执行对static静态变量count的修改。
在inc()方法中,对count用for循环执行操作很重要。因为现在的电脑性能都应经很好(一般情况下资源都浪费了),所以如果简单地执行一次count++的话,又没有一些线程和它竞争CPU,所以很有可能看不到实验的结果。(我的机器就是这种情况,找我们项目组的哥问了才了解)。

线上一张图,然后再说:(图片来自:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html)<----他的这篇文章有问题,可以说代码根本和他说的对不上,下面再喷他,但是他的分析是对的。



我们的用循环新开的线程肯定不是主线程。所以我们的子线程要去访问count变量,就是这样,read -> load -> use -> assign -> store -> write.

read 和load一下子就OK了,但是use,assign,store是对自己现成的这块内存的操作,是可以进行很多次和需要时间的。

那么问题容易出现在什么地方呢,就出在这块时间上,世界并不是静止的,计算机也一样。你操作的这段时间,其他的进程也可以操作(因为你并没有加锁同步)。街上的美女又不是只有你可以看,对不对。

好了,这就是问题所在。执行这段代码的时候一个线程拿到了主线程内存中的count的拷贝,然后要进行1000次加操作。可是1000次还没干完呢,又来了个线程得到了最新的count的拷贝,也进行1000加操作。但是第二个进程得到的拷贝并不是1000,可能只有209.好了,解释到这里就可以了。

然后最后打印出最后的count的值,验证代码。

开始喷(轻喷)。上图的作者的代码里面,没有:

for (Thread t : ts) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

这段代码,然后就输出,就说怎么地怎么地。问什么不对很简单,这段代码的作用是让主进程在所有子进程执行完之后执行。如果子进程没执行完就把半路上的count输出,效果虽然跟没同步是一样的但是绝不是那么回事。
关于让主进程在子进程之后执行的方法主要有两个,以后再说。哦,对了,join()的意思是:“等待该线程执行完之后再执行”,将主语和宾语带入,就是:“等待我子线程执行完之后你主线程再执行”。

(如果把join用在产生新线程的for循环中的话你会发现线程ID都是排的整整齐齐的呢。。。。为什么应该不难理解)

接下来想想,同步的话怎么搞呢?

synchrinized放在public和static之间就好(这么详细我也醉了)。然后运行一下看看,你就懂了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息