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

    声明:文章内容全都是自己的学习总结,如有不对的地方请大家帮忙指出。有需要沟通交流的可加我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。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值