保存到桌面加入收藏设为首页
IOS开发
当前位置:首页 > IOS开发

由一个多线程共享Integer类变量问题引起的。。。-安度博客

时间:2019-02-08 15:56:49   作者:   来源:   阅读:131   评论:0
内容摘要:  最近看到一个多线程面试题,有三个线程分别打印A、B、C请用多线程编程实现,在屏幕上循环打印10次ABCABC…  看到这个题目,首先想到的是解决方法是定义一个Integer类对象,初始化为0,由3个线程共享,如果Integer对象取余3之后等于0,则打印A,同时......
  •   最近看到一个多线程面试题,有三个线程分别打印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(); } } } }}


本站所有站内信息仅供娱乐参考,不作任何商业用途,不以营利为目的,专注分享快乐,欢迎收藏本站!
所有信息均来自:百度一下 (威尼斯人官网)