您的位置:首页 > 其它

多线程学习总结(七)——线程安全之共享变量

2016-10-06 16:52 288 查看
声明:文章内容全都是自己的学习总结,如有不对的地方请大家帮忙指出。有需要沟通交流的可加我QQ群:425120333

在并发编程中,通常要注意三个问题:原子性问题、可见性问题、有序性问题,关于这三个问题的详细解释,可参考:http://www.cnblogs.com/dolphin0520/p/3920373.html
对这三个有个基本的了解之后,再来讨论共享变量的问题,共享变量分为2种情况(我暂时只碰到这两种,可能还有其他的)
第一种多线程类中的静态变量:


public class TestShareVariables {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new ShareDemo()).start();
}

//这里加个睡眠时间是为了保证让前面的线程类有足够时间运行好
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(ShareDemo.getCount());
}
}

/**
* @author pc_cqb
*
* @introduce 补充一点实现多线程时默认都是实现Runnable接口,
* 而不是继承Thread类, 原因是java中接口是可以多实现的,
* 而类只能是单继承。
*
*/
class ShareDemo implements Runnable {

//如果要让这个变量在各个线程类中共享,需要将该变量声明为类变量,加上static关键字
//否则每次new 出来的对象都会有自己的变量
private static int count = 0;

public static int getCount() {
return count;
}

@Override
public void run() {
for (int i = 0; i < 10; i++) {
count++;

//这里加个线程时间是为了避免一个线程在获取到时间片时一次就运行完
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


控制台输出

46

这个输出结果每次可能都是不一样的反正是一个小于50的数(等于50的概率基本为0,但不是没有),而按照代码中的理解我们是希望输出结果是50的,

导致出现这种问题的原因是count++操作无法保证原子性,可见性。所以,在多线程操作中只有三个都满足了,才能保证共享变量之间不会出现问题。

至于上述代码怎么改进,才能不出现问题,这里先卖个关子,不讨论,下一篇再来说明(解决办法不唯一,大家考虑下)。

第二种多线程类中的普通变量,通过构造方法获取同一变量:

public class TestShareVariables {
public static void main(String[] args) {
Count count = new Count();
for (int i = 0; i < 5; i++) {
new Thread(new ShareDemo(count)).start();
}

//这里加个睡眠时间是为了保证让前面的线程类有足够时间运行好
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count.getCount());
}
}

class Count {
private int countNum = 0;

public void incCount() {
for (int i = 0; i < 10; i++) {
countNum++;
//这里加个线程时间是为了避免一个线程在获取到时间片时一次就运行完
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public int getCount() {
return countNum;
}
}

class ShareDemo implements Runnable {

private Count count;

public ShareDemo(Count count) {
this.count = count;
}

@Override
public void run() {
count.incCount();
}
}


控制台输出

44

这里的虽然每个线程中都是用同一个Count对象,但是由于每个线程都对countNum进行累加时无法保证其他对象对其不操作,

所以使得最后的结果也是比预计结果小,达不到50。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: