热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

由一个多线程共享Integer类变量问题引起的。。。

最近看到一个多线程面试题,有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…看到这个题目,首先想到的是解决方法是定义一个Integer类对象,初始化为0

  最近看到一个多线程面试题,有三个线程分别打印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();
}
}
}
}
}

 


推荐阅读
author-avatar
sl51866
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有