
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
昆明达内的老师最近看到一个多线程面试题,有三个线程分别打印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个线程测试*/publicclassThreeThread {publicstaticvoidmain(String[] args)throwsInterruptedException { Integer gData= 0; Thread thread1=newMyTask(gData, 0, "A"); Thread thread2=newMyTask(gData, 1, "B");
Thread thread3=newMyTask(gData, 2, "C"); thread1.start();
thread2.start(); thread3.start();
thread1.join(); thread2.join(); thread3.join(); } }classMyTaskextendsThread {privateInteger gData;privateintn;privateString info;publicMyTask(Integer gData,intn, String info) {super("thread " +info);this.gData =gData;this.n =n;# =info; }publicvoidrun()
{inti = 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 {@codeInteger}. * *@serial*/privatefinalintvalue;
也就是说,Integer类对象的值每更新一次,就会创建一个新的Integer对象。运行程序结果只打印出了"A",表示刚开始A、B、C线程都拥有同一个Integer类变量,并且初值为0,但是当A线程更新Integer对象的值后,A线程中的Integer对象和B/C线程中的Integer对象已经不是同一个对象了。
为了能够正常打印出ABCABC字符串,可以把Integer对象类型改为AtomicInteger,代码如下:
/*** ThreeThread * 3个线程测试*/publicclassThreeThread {publicstaticvoidmain(String[] args)throwsInterruptedException {
AtomicInteger gData=newAtomicInteger(0); Thread thread1=newMyTask(gData, 0, "A"); Thread thread2=newMyTask(gData,
1, "B"); Thread thread3=newMyTask(gData, 2, "C"); thread1.start(); thread2.start();
thread3.start(); thread1.join(); thread2.join(); thread3.join(); } }classMyTaskextendsThread {privateAtomicInteger
gData;privateintn;privateString info;publicMyTask(AtomicInteger
gData,intn, String info)
{super("thread " +info);this.gData =gData;this.n =n;# =info; }publicvoidrun() {inti = 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,使用线程同步方式*/publicclassThreeThread2{publicstaticvoidmain
String[]args)throwsInterruptedException { Object A=newObject();Object B=newObject();
Object C=newObject();
MyThread myThread1=newMyThread(C, A, "A"); MyThread myThread2=newMyThread(A, B, "B"); MyThread myThread3=newMyThread(B, C, "C"); myThread1.start(); Thread.sleep(10); myThread2.start();
Thread.sleep(10); myThread3.start();try{
myThread1.join(); myThread2.join(); myThread3.join();}catch(InterruptedExceptione)
{ e.printStackTrace(); } } }classMyThreadextendsThread {privateObject prev;privateObject curr;privateString info;publicMyThread(Object prev, Object curr, String info)
{this.prev =prev;this.curr =curr;# =info;
}publicvoidrun() {intcnt = 10;while(cnt-- > 0) {synchronized(prev){synchronized(curr){
System.out.print(info+ " ");
curr.notify(); }try{ prev.wait(); }catch(InterruptedException e) { e.printStackTrace(); } } } } }