由一个多线程共享Integer类变量问题引起的。。。
最近看到一个多线程面试题,有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…
看到这个题目,首先想到的是解决方法是定义一个Integer类对象,初始化为0,由3个线程共享,如果Integer对象取余3之后等于0,则打印A,同时进行加1操作;如果Integer对象取3之后等于1,则打印B,同时进行加1操作;如果Integer对象取3之后等于1,则打印C,如果循环打印了10次的话,就退出线程。
/**
* ThreeThread
* 3个线程测试
*/
public class ThreeThread { public static void main(String[] args) throws InterruptedException {
Integer gData = 0;
Thread thread1 = new MyTask(gData, 0, "A");
Thread thread2 = new MyTask(gData, 1, "B");
Thread thread3 = new MyTask(gData, 2, "C"); thread1.start();
thread2.start();
thread3.start(); thread1.join();
thread2.join();
thread3.join();
} } class MyTask extends Thread { private Integer gData;
private int n;
private String info; public MyTask(Integer gData, int n, String info) {
super("thread " + info);
this.gData = gData;
this.n = n;
this.info = info;
} public void run() {
int i = 0; while (true) {
synchronized (gData) {
if (gData % 3 == n) {
System.out.print(info + " ");
gData++;
i++;
}
} if (i == 10) {
break;
}
else {
Thread.yield();
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} }
运行程序结果如下:

发现只有A线程打印了"A",并没有发现B线程和C线程打印字符串:(。难道是A线程更改了Integer对象的值,而B线程和C线程并没有“看到”更新后的值?于是,在线程类的run方法的while循环中增加代码如下:
while (true) {
System.out.println(Thread.currentThread().getName() + " " + gData);
synchronized (gData) {
if (gData % 3 == n) {
System.out.print(info + " ");
gData++;
i++;
}
}
...
}
运行程序结果如下:

由运行结果可知,刚开始A、B、C线程都拥有Integer类变量,并且初值为0。当A线程更改Integer类变量为1时,但是B和C线程中的Integer类变量的值仍然为0,因此,结果肯定不会打印出ABCABC....
通过阅读Integer类源码,可知Integer类中存放int值的变量类型是final的:
/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;
也就是说,Integer类对象的值每更新一次,就会创建一个新的Integer对象。运行程序结果只打印出了"A",表示刚开始A、B、C线程都拥有同一个Integer类变量,并且初值为0,但是当A线程更新Integer对象的值后,A线程中的Integer对象和B/C线程中的Integer对象已经不是同一个对象了。
为了能够正常打印出ABCABC字符串,可以把Integer对象类型改为AtomicInteger,代码如下:
/**
* ThreeThread
* 3个线程测试
*/
public class ThreeThread { public static void main(String[] args) throws InterruptedException {
AtomicInteger gData = new AtomicInteger(0);
Thread thread1 = new MyTask(gData, 0, "A");
Thread thread2 = new MyTask(gData, 1, "B");
Thread thread3 = new MyTask(gData, 2, "C"); thread1.start();
thread2.start();
thread3.start(); thread1.join();
thread2.join();
thread3.join();
} } class MyTask extends Thread { private AtomicInteger gData;
private int n;
private String info; public MyTask(AtomicInteger gData, int n, String info) {
super("thread " + info);
this.gData = gData;
this.n = n;
this.info = info;
} public void run() {
int i = 0; while (true) {
synchronized (gData) {
if (gData.get() % 3 == n) {
System.out.print(info + " ");
gData.incrementAndGet();
i++;
}
} if (i == 10) {
break;
}
else {
Thread.yield();
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} }

第二种打印ABCABC...字符串的解决方法是使用wait/notify函数,示例代码如下:
/**
* ThreeThread2
* 三个线程依次输出A B C,使用线程同步方式
*/
public class ThreeThread2 { public static void main(String[] args) throws InterruptedException {
Object A = new Object();
Object B = new Object();
Object C = new Object(); MyThread myThread1 = new MyThread(C, A, "A");
MyThread myThread2 = new MyThread(A, B, "B");
MyThread myThread3 = new MyThread(B, C, "C"); myThread1.start();
Thread.sleep(10);
myThread2.start();
Thread.sleep(10);
myThread3.start(); try {
myThread1.join();
myThread2.join();
myThread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} } class MyThread extends Thread {
private Object prev;
private Object curr;
private String info; public MyThread(Object prev, Object curr, String info) {
this.prev = prev;
this.curr = curr;
this.info = info;
} public void run() {
int cnt = 10; while (cnt-- > 0) {
synchronized (prev) {
synchronized (curr) {
System.out.print(info + " ");
curr.notify();
} try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

由一个多线程共享Integer类变量问题引起的。。。的更多相关文章
- 并行编程之多线程共享非volatile变量,会不会可能导致线程while死循环
背景 大家都知道线程之间共享变量要用volatilekeyword.可是,假设不用volatile来标识,会不会导致线程死循环?比方以下的伪代码: static int flag = -1; void ...
- 用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1
package com.ljn.base; /** * @author lijinnan * @date:2013-9-12 上午9:55:32 */ public class IncDecThrea ...
- python编程系列---多线程共享全局变量出现了安全问题的解决方法
多线程共享全局变量出现了安全问题的解决方法 当多线程共享全局变量时,可能出现安全问题,解决机制----互斥锁:即在在一段与全局变量修改相关的代码中,假设一个时间片不足以完成全局变量的修改,就在这段代码 ...
- Delphi另一个多线程函数:BeginThread用法
Delphi另一个多线程函数:BeginThread━━━━━━━━━━━━━━━━━━━━━━━━━━ Delphi也提供了一个相同功能的类似函数:function BeginThread( ...
- JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池
/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两 ...
- Python 中多线程共享全局变量的问题
写在前面不得不看的一些P话: Python 中多个线程之间是可以共享全局变量的数据的. 但是,多线程共享全局变量是会出问题的. 假设两个线程 t1 和 t2 都要对全局变量g_num (默认是0)进行 ...
- 用 python 实现一个多线程网页下载器
今天上来分享一下昨天实现的一个多线程网页下载器. 这是一个有着真实需求的实现,我的用途是拿它来通过 HTTP 方式向服务器提交游戏数据.把它放上来也是想大家帮忙挑刺,找找 bug,让它工作得更好. k ...
- python_way ,day11 线程,怎么写一个多线程?,队列,生产者消费者模型,线程锁,缓存(memcache,redis)
python11 1.多线程原理 2.怎么写一个多线程? 3.队列 4.生产者消费者模型 5.线程锁 6.缓存 memcache redis 多线程原理 def f1(arg) print(arg) ...
- C++实现一个多线程同步方式的协同工作程序示例
多线程并发程序与协同程序其实是不同的概念.多线程并发是多个执行序同时运行,而协同程序是多个执行序列相互协作,同一时刻只有一个执行序列.今天想到的是将两者结合起来,拿现实生活中的例子来说,假设一个班级有 ...
随机推荐
- JavaScript权威设计--CSS(简要学习笔记十六)
1.Document的一些特殊属性 document.lastModified document.URL document.title document.referrer document.domai ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(8)-MVC与EasyUI DataGrid 分页
系列目录 前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 EasyUI Datagrid在加载的时候会提交一些分页的信息到后台,我们需要根据这些信息来进行数据分页再次返回到前台 实 ...
- H5 Notes:Navigator Geolocation
H5的地理位置API可以帮助我们来获取用户的地理位置,经纬度.海拔等,因此我们可以利用该API做天气应用.地图服务等. Geolocation对象是我们获取地理位置用到的对象. 首先判断浏览器是否支持 ...
- Solr Facet 默认值
前言 今天在用Solr Facet遇到了默认值的问题,我用Facet.field查询发现数据总共100条,刚开始没有注意,发现少个别数据,但是用这几个个别的id查询又能查出来数据.才发现是Facet默 ...
- Bloom Filter:海量数据的HashSet
Bloom Filter一般用于数据的去重计算,近似于HashSet的功能:但是不同于Bitmap(用于精确计算),其为一种估算的数据结构,存在误判(false positive)的情况. 1. 基本 ...
- 结合ABP源码实现邮件发送功能
1. 前言 2. 实现过程 1. 代码图(重) 2.具体实现 2.1 定义AppSettingNames及AppSettingProvider 2.2 EmailSenderConfiguration ...
- Rafy 框架 - 流水号插件
Rafy 框架又添新成员:流水号插件.本文将解释 Rafy 框架中的流水插件的场景.使用方法. 场景 在开发各类数据库应用系统时,往往需要生成从一开始的流水号,有时还需要按月或者按日进行独立生成,如下 ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- JavaWeb_day04搜索_乱码_路径_转发重定向_cookie
本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! 搜索功能 DAO层都是一些数据库的增删改查操作 Ser ...
- 最小生成树计数 bzoj 1016
最小生成树计数 (1s 128M) award [问题描述] 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一 ...