建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。
2013-08-16 14:15
411 查看
/** * 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。 * 这个问题用Object的wait(),notify()就可以很方便的解决。 * * 主要的思想就是,为了控制执行的顺序,必须要先持有prev锁,也就前一个线程要释放自身对象锁,再去申请自身对象锁, * 两者兼备时打印,之后首先调用self.notify()释放自身对象锁,唤醒下一个等待线程,再调用prev.wait()释放prev对象锁, * 终止当前线程,等待循环结束后再次被唤醒。 * * 程序运行的主要过程就是A线程最先运行,持有C,A对象锁,后释放A,C锁,唤醒B。线程B等待A锁,再申请B锁,后打印B, * 再释放B,A锁,唤醒C,线程C等待B锁,再申请C锁,后打印C,再释放C,B锁,唤醒A。 * * wait导致当前的线程等待,直到其他线程调用此对象的 notify() 要领或 notifyAll() 要领。当前的线程必须拥有此对象监视器。该线程揭晓对此监视器的一切权并等待,直到其他线程议决调用 notify 要领,或 notifyAll 要领告诉在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得 对监视器的一切权后才能继续执行. notify唤醒在此对象监视器上等待的单个线程。假如一切线程都在此对象上等待,则会挑选唤醒其中一个线程。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。此要领只应由作为此对象监视器的一切者的线程来调用. "当前的线程必须拥有此对象监视器"与"此要领只应由作为此对象监视器的一切者的线程来调用"表明 wait要领与notify要领必须在同步块内执行,即synchronized(obj之内). 调用对像wait要领后,当火线程释放对像锁,进入等待形状 .直到其他线程(也只好是其他线程)议决 notify 要领,或 notifyAll.该线程重新获得 对像锁. 继续执行,记得线程必须重新获得 对像锁才能继续执行.由于 synchronized代码块内没有锁是寸步无法走的. notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。两者的最大区别在于: notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。 notify则文明得多他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。 */ package t; public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private MyThreadPrinter2(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 10; while (count > 0) { //同步块,加锁 synchronized (prev) { synchronized (self) { System.out.print(name); count--; /* try{ Thread.sleep(1); } catch (InterruptedException e){ e.printStackTrace(); }*/ self.notify(); //唤醒在此对象监视器上等待的单个线程(即等待给self加锁的线程)。假如多个线程都在此对象上等待,则会挑选唤醒其中一个线程。 }//self解锁,被唤醒的线程此时可以给self加锁了。 try { prev.wait(); //该线程暂时释放prev的锁,等待再次获得prev的锁,然后执行下面的语句。此时prev还需要被唤醒 } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { Object a = new Object(); Object b = new Object(); Object c = new Object(); MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a); MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b); MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c); new Thread(pa).start();//c a加锁,a输出'A',a唤醒pb,a解锁(synchronized (a){}同步块结束),c.wait()->该线程pa等待(c暂时解锁,直至其它线程执行c.notify()之后,该线程pa才能继续执行(即被唤醒)---可以理解为等待c的通知) Thread.sleep(10);//在单线程下,Thread.sleep(10000)让你的线程“睡眠”10000ms,也就是不工作,因为是单线程,所以要等到过了10000ms之后,该子线程继续工作。 //多线程下,睡眠的线程main先不工作,让其余的子线程先工作,等过了10000ms之后,它再重新回到线程的等待队伍中,开始工作。 //main睡眠10ms结束后,执行下面的语句,即new Thread(pb).start();----pb线程启动后,main再睡眠10ms,接着启动pc。这样不让pb和pc相邻启动,避免pc和pb竞争(因为开始时pc和pb都符合条件) new Thread(pb).start();//a b加锁,b输出'B',b唤醒pc,b解锁,a.wait()->该线程pb等待(c暂时解锁,直至其它线程执行a.notify()之后,该线程pb才能继续执行) Thread.sleep(10); new Thread(pc).start();//b c加锁,c输出'C',c唤醒pa,c解锁,b.wait()->该线程pc等待(b暂时解锁,直至其它线程执行b.notify()之后,该线程pc才能继续执行) Thread.sleep(10); } }
相关文章推荐
- 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。
- 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC
- 建立m个线程,每个线程只能打印一种字符,要求纯种同时运行,交替打印n次字符
- 多线程(至少三个线程)分别打印A、B、C,要求按ABC的顺序循环打印10次。
- java多线程面试题:三个线程顺序打印ABC,重复10次
- 三个线程循环打印ABC10次的几种解决方法
- 题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕打印10次ABC
- 三个线程循环打印ABC10次的几种解决方法
- Semaphore实现的三个线程协作循环打印10次ABC的方法
- 控制三个线程交替打印ABC
- 有三个线程A、B、C(线程名称或id),循环打印10次ABCABB…
- 三个线程交替打印ABC
- 面试题--三个线程循环打印ABC10次的几种解决方法
- 有三个线程名字分别是A、B、C,每个线程只能打印自己的名字,在屏幕上顺序打印 ABC,打印10次。不准使用线程的sleep()
- 两个线程A和B,任务都是打印当前时间,要求编码实现:线程A和B同时启动后,以先A后B的方式任务交叉执行10次。
- 有三个线程ID分别是A、B、C,请有多线编程 实现 在屏幕上循环打印10次ABCABC......
- 有三个线程名字分别是A、B、C,每个线程只能打印自己的名字,在屏幕上顺序打印 ABC,打印10次。
- 有三个线程ID分别是A、B、C,请有多线编程实现,在屏幕上循环打印10次ABCABC
- 启动三个线程A,B,C,打印10次 按照ABC的顺序输出
- 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。如:ABCABCABC…… 依次递归