多线程学习总结(七)——线程安全之共享变量
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。
相关文章推荐
- 多线程实现资源共享的问题学习与总结
- 多线程学习总结(八)——线程安全之“”锁“”
- 多线程实现资源共享的问题学习与总结
- 多线程实现资源共享的问题学习与总结
- 关于进程和线程对于全局变量共享的问题学习总结
- 多线程学习总结(十)——线程安全之线程间的通信深入
- 关于进程和线程对于全局变量共享的问题学习总结
- 从头认识多线程-1.2 共享变量与线程安全简介
- 张孝祥[致敬]-多线程学习第05课-线程范围内的共享变量
- 张孝祥[致敬]-多线程学习第06课-多个线程之间的共享变量
- 多线程学习之一:线程对共享全局变量的访问
- 多线程学习总结(十一)——线程安全之线程间的通信notify和notifyAll
- 多线程学习总结(九)——线程安全之线程间的通信
- 多线程实现资源共享的问题学习与总结
- 多线程实现资源共享的问题学习与总结
- JAVA学习之多线程--共享变量
- Java 多线程学习总结3
- .Net学习难点讨论系列14 – 多线程下的进程同步(线程同步问题总结篇)
- Java 多线程学习总结6
- Java 多线程学习总结3.1