一个多线程分别打印abc的问题

welen 2014-03-06 09:09:22
运行这段代码,前面可以打印两三次abc,然后就卡住了,初步估计应该都进入wait了,但是不明白为什么,求指导
public class TestDemo {

public static void main(String[] args) {
final Locker p = new Locker();
Task11 a = new Task11(p);
Task21 b = new Task21(p);
Task31 c = new Task31(p);
Thread one = new Thread(a);
one.start();
Thread two = new Thread(b);
two.start();
Thread three = new Thread(c);
three.start();
}
}


class Task11 implements Runnable {

private Locker obj;
public Task11(Locker p){
this.obj = p;
}

@Override
public void run() {
for(int i = 0; i < 5; i++){
synchronized (obj) {
if(obj.num != 0){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println("a");
obj.num = 1;
obj.notifyAll();
}
}
}
}
}
class Task21 implements Runnable {

private Locker obj;
public Task21(Locker p){
this.obj = p;
}

@Override
public void run() {
for(int i = 0; i < 5; i++){
synchronized (obj) {
if(obj.num != 1){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println("b");
obj.num = 2;
obj.notifyAll();
}
}
}
}
}
class Task31 implements Runnable {

private Locker obj;
public Task31(Locker p){
this.obj = p;
}

@Override
public void run() {
for(int i = 0; i < 5; i++){
synchronized (obj) {
if(obj.num != 2){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println("c");
obj.num = 0;
obj.notifyAll();
}
}
}
}
}

class Locker {
int num = 0;
}
...全文
235 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
陆荃 2014-03-06
  • 打赏
  • 举报
回复
问题分析: for循环可能会执行到wait分支,故不可能打印所有的5个a(或者b,c)。 至于程序有时(占大比例)会停住,是因为比如task11已经跑完for循环,而此时task21,31均处于wait状态,没有地方触发notifyAll,所以会停住。 解决方法: 问题关键点在于for循环的5次肯定不能输出五次a,b,c。 愚以为,作如下改动能实现楼主要求: public class TestDemo { public static void main(String[] args) { final Locker p = new Locker(); Task11 a = new Task11(p); Task21 b = new Task21(p); Task31 c = new Task31(p); Thread one = new Thread(a, "Task11"); one.start(); Thread two = new Thread(b, "Task21"); two.start(); Thread three = new Thread(c, "Task31"); three.start(); } } class Task11 implements Runnable { private Locker obj; public Task11(Locker p) { this.obj = p; } @Override public void run() { int i = 0; while (true) { synchronized (obj) { if (obj.num != 0) { try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("a"); obj.num = 1; obj.notifyAll(); if (4 == i++) break; } } } } } class Task21 implements Runnable { private Locker obj; public Task21(Locker p) { this.obj = p; } @Override public void run() { int i = 0; while (true) { synchronized (obj) { if (obj.num != 1) { try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("b"); obj.num = 2; obj.notifyAll(); if (4 == i++) break; } } } } } class Task31 implements Runnable { private Locker obj; public Task31(Locker p) { this.obj = p; } @Override public void run() { int i = 0; while (true) { synchronized (obj) { if (obj.num != 2) { try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("c"); obj.num = 0; obj.notifyAll(); if (4 == i++) break; } } } } } class Locker { int num = 0; } 浅薄之见,还望指教。
nmyangym 2014-03-06
  • 打赏
  • 举报
回复
我的粗浅看法: 楼主这样的逻辑,用while 好一些。看下面的代码:

public class TestDemo {
	 
    public static void main(String[] args) {
        final Locker p = new Locker();
        Task11 a = new Task11(p);
        Task21 b = new Task21(p);
        Task31 c = new Task31(p);
        Thread one = new Thread(a);
        one.start();
        Thread two = new Thread(b);
        two.start();
        Thread three = new Thread(c);
        three.start();
    }
}
 
 
class Task11 implements Runnable {
     
    private Locker obj;
    public Task11(Locker p){
        this.obj = p;
    }
     
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            synchronized (obj) {
                while(obj.num != 0){//if 改成while,只要num != 0, 肯定等待。
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //必须num == 0 , 才执行。
                System.out.println("a");
                obj.num = 1;
                obj.notifyAll();
            }
        }
    }
}
class Task21 implements Runnable {
     
    private Locker obj;
    public Task21(Locker p){
        this.obj = p;
    }
     
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            synchronized (obj) {
                while(obj.num != 1){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("b");
                obj.num = 2;
                obj.notifyAll();
            }
        }
    }
}
class Task31 implements Runnable {
     
    private Locker obj;
    public Task31(Locker p){
        this.obj = p;
    }
     
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            synchronized (obj) {
                while(obj.num != 2){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("c");
                obj.num = 0;
                obj.notifyAll();
            }
        }
    }
}
 
class Locker {
    int num = 0;
}
如果不用while, 需要这样改:

public class TestDemo {
	 
    public static void main(String[] args) {
        final Locker p = new Locker();
        Task11 a = new Task11(p);
        Task21 b = new Task21(p);
        Task31 c = new Task31(p);
        Thread one = new Thread(a);
        one.start();
        Thread two = new Thread(b);
        two.start();
        Thread three = new Thread(c);
        three.start();
    }
}
 
 
class Task11 implements Runnable {
     
    private Locker obj;
    public Task11(Locker p){
        this.obj = p;
    }
     
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            synchronized (obj) {
                if(obj.num != 0){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒时判断num值,是0,执行输出;否则,本次唤醒无意义,需要把i减一,继续循环。而用while 就比较好。楼主试一下。
                    if(obj.num == 0){
                    	System.out.println("a");
                        obj.num = 1;
                        obj.notifyAll();
                    }
                    else {
                    	i--;
                    }
                }
                else {
                	System.out.println("a");
                    obj.num = 1;
                    obj.notifyAll();
                }
            }
        }
    }
}
class Task21 implements Runnable {
     
    private Locker obj;
    public Task21(Locker p){
        this.obj = p;
    }
     
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            synchronized (obj) {
                if(obj.num != 1){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(obj.num == 1){
                    	System.out.println("b");
                        obj.num = 2;
                        obj.notifyAll();
                    }
                    else {
                    	i--;
                    }
                }
                else {
                	System.out.println("b");
                    obj.num = 2;
                    obj.notifyAll();
                }
            }
        }
    }
}
class Task31 implements Runnable {
     
    private Locker obj;
    public Task31(Locker p){
        this.obj = p;
    }
     
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            synchronized (obj) {
                if(obj.num != 2){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(obj.num == 2){
                    	System.out.println("c");
                        obj.num = 0;
                        obj.notifyAll();
                    }
                    else {
                    	i--;
                    }
                }
                else {
                	System.out.println("c");
                    obj.num = 0;
                    obj.notifyAll();
                }
            }
        }
    }
}
 
class Locker {
    int num = 0;
}
tony4geek 2014-03-06
  • 打赏
  • 举报
回复
你理解下

public class TestDemo {
	 public static void main(String[] args) {
	        final Locker p = new Locker();
	        Task11 a = new Task11(p);
	        Task21 b = new Task21(p);
	        Task31 c = new Task31(p);
	        Thread one = new Thread(a);
	        one.start();
	        Thread two = new Thread(b);
	        two.start();
	     //   Thread three = new Thread(c);
	     //   three.start();
	    }
	}
	 
	 
	class Task11 implements Runnable {
	     
	    private Locker obj;
	    public Task11(Locker p){
	        this.obj = p;
	    }
	     
	    @Override
	    public void run() {
	        for(int i = 0; i < 5; i++){
	            synchronized (obj) {
	                if(obj.num != 0){
	                    try {
	                        obj.wait();
	                    } catch (InterruptedException e) {
	                        e.printStackTrace();
	                    }
	                }else{
	                    System.out.println("a");
	                    obj.num = 1;
	                    obj.notifyAll();
	                }
	            }
	        }
	    }
	}
	class Task21 implements Runnable {
	     
	    private Locker obj;
	    public Task21(Locker p){
	        this.obj = p;
	    }
	     
	    @Override
	    public void run() {
	        for(int i = 0; i < 5; i++){
	            synchronized (obj) {
	                if(obj.num != 1){
	                    try {
	                        obj.wait();
	                    } catch (InterruptedException e) {
	                        e.printStackTrace();
	                    }
	                }else{
	                    System.out.println("b");
	                    obj.num = 0;
	                    obj.notifyAll();
	                }
	            }
	        }
	    }
	}

	class Task31 implements Runnable {
	     
	    private Locker obj;
	    public Task31(Locker p){
	        this.obj = p;
	    }
	     
	    @Override
	    public void run() {
	        for(int i = 0; i < 5; i++){
	            synchronized (obj) {
	                if(obj.num != 2){
	                    try {
	                        obj.wait();
	                    } catch (InterruptedException e) {
	                        e.printStackTrace();
	                    }
	                }else{
	                    System.out.println("c");
	                    obj.num = 0;
	                    obj.notifyAll();
	                }
	            }
	        }
	    }
	}
	 
	class Locker {
	    int num = 0;
	}
welen 2014-03-06
  • 打赏
  • 举报
回复
引用 1 楼 rui888 的回复:
one two three 的调度顺序问题。
怎么改,按我理解,每次三个线程中总有一个执行了else的代码块,然后通过notifyall唤醒所有等待的,下一次应该就只有num指定的线程可以执行else的代码了。。这样每次都可以有一个else可以得到执行。。事实不是这样,所以不理解了,能说清楚吗
tony4geek 2014-03-06
  • 打赏
  • 举报
回复
one two three 的调度顺序问题。
faker-_- 2014-03-06
  • 打赏
  • 举报
回复
测试了一下,每个线程都去掉else就可以了。因为假如A线程在sleep被唤醒时,它只会进行执行if下面的程序,而if下面没有唤醒其他线程的代码,这样所有的代码都是出于sleep状态了。

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧