java多线程阻塞等待问题

bigPig_ink 发布于 2017/07/07 11:45
阅读 358
收藏 0

package liuhuan.test;

public class TestThread {

	static class A implements Runnable{
		int a = 0;
		Notify n;
		
		public void run () {
			for (int i=0;i<10;i++) {
				a++;
				System.out.println("a=" + a);
				if (a == 3) {
					//第三次触发B的等待事件
					n.waitAction();
				}
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	static class B implements Runnable{
		int b = 0;
		Notify n;
		public void run () {
			for (int i=0;i<10;i++) {
				b++;
				System.out.println("b=" + b);
				if (3 == b) {
					//第三次需要等待A指定事件的执行
					n.notifyAction();
				}
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	static class Notify {
		boolean x = false;
		B b;
		public Notify (B b) {
			this.b = b;
		}
		
		public void waitAction() {
			if (!x) {
				System.out.println(Thread.currentThread() + "触发休眠");
				try {
					Thread.sleep(10);
					synchronized (b) {
						b.wait();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}
		
		public void notifyAction() {
			System.out.println(Thread.currentThread() + "触发唤醒");
			x = true;
			synchronized (b) {
				b.notify();
			}
		}
		
	}
	
	public static void main(String[] args) {
		B b = new B();
		Notify n = new Notify(b);
		A a = new A();
		a.n = n;
		b.n = n;
		new Thread(a).start();
		new Thread(b).start();
	}

}

这段代码模拟实现上图的业务,但是还是存在问题:

【请问】有哪位大神有更好的办法或者改进下

加载中
0
DeMoNHaDeS
DeMoNHaDeS

a线程先进入waitAction的synchronized块,调用wait方法等待。b线程进入notifyAction方法时候无法进入synchronized块。

bigPig_ink
bigPig_ink
回复 @DeMoNHaDeS : 【1】如果你的意思是A执行完再执行B?这样肯定没问题,但是相应的,多线程就没有意义了! 【2】如果你的意思是两个线程同时执行,比如B到了等待点的时候发现A才到指定触发点(A触发点没执行),这个时候按照我上面代码逻辑,会导致B一直等待,但不知道你的思路是什么,最好可以代码实现下哦
DeMoNHaDeS
DeMoNHaDeS
回复 @bigPig_ink : 所以你想实现的其实是一个先后顺序的问题,让b等待a执行,因此实现的思路有问题。a是不需要锁的。可以简单通过一个公用的变量x,a执行完成后修改x,b等待,直到x被修改
bigPig_ink
bigPig_ink
补充下,上面说的有点问题,不是两个方法同步,是需要确保waitAction方法中if (!x) {到b.wait();是个整体,期间不能执行notifyAction,应该是这样
bigPig_ink
bigPig_ink
这个是:进入waitAction是,执行通过了if(!x)的判断后同时notifyAction被执行并且在waitAction方法的b.wait();前执行完,就会出现无法唤醒!为了扩大概率,所以加了sleep10s 我就是不知道如何才能精准唤醒,也就是确保waitAction和notifyAction只有各自在完全执行完或者执行前才能调用,也就是这两个方法需要同步锁!
0
DeMoNHaDeS
DeMoNHaDeS

引用来自“DeMoNHaDeS”的评论

a线程先进入waitAction的synchronized块,调用wait方法等待。b线程进入notifyAction方法时候无法进入synchronized块。


    static class Notify {
        volatile boolean x = false;
        B b;

        public Notify(B b) {
            this.b = b;
        }

        public void waitAction() {
            try {
                synchronized (b) {
                    System.out.println(Thread.currentThread() + "触发休眠");
                    x = true;
                    b.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void notifyAction() {
            try {
                while (!x) {
                    Thread.sleep(10);
                }
                synchronized (b) {
                    System.out.println(Thread.currentThread() + "触发唤醒");
                    b.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

 

0
bigPig_ink
bigPig_ink

@DeMoNHaDeS 多谢,明白了,之前没理解完全理解synchronized关键字对于wait()和notify()方法的作用,哈哈,只要保证waitAction()先执行就OK了

对象b在进入waitAction()的代码块时被锁住,故不能执行notifyAction()的同步代码块;当waitAction()中“b.wait();”执行后,锁被释放,这时notifyAction()的代码块执行...

0
bigPig_ink
bigPig_ink

引用来自“DeMoNHaDeS”的评论

a线程先进入waitAction的synchronized块,调用wait方法等待。b线程进入notifyAction方法时候无法进入synchronized块。

引用来自“DeMoNHaDeS”的评论


    static class Notify {
        volatile boolean x = false;
        B b;

        public Notify(B b) {
            this.b = b;
        }

        public void waitAction() {
            try {
                synchronized (b) {
                    System.out.println(Thread.currentThread() + "触发休眠");
                    x = true;
                    b.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void notifyAction() {
            try {
                while (!x) {
                    Thread.sleep(10);
                }
                synchronized (b) {
                    System.out.println(Thread.currentThread() + "触发唤醒");
                    b.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

 

多谢大神指点...有所收获

返回顶部
顶部