线程 程序
是一段静态的代码,它是应用软件执行的蓝本。进程
是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡(完成)的过程。线程
是比进程更小的执行单位。一个进程在其执行过程中,可以产生多个线程,形成多条执行线索。每条线索(即每个线程)有它自身的产生、发展和消亡(完成)的过程,也是一个动态的概念。
Java程序从主类(main class,main方法所在的类)的main()方法开始执行 当JVM加载代码,发现main()方法后,就会启动一个线程,称作“主线程”
,该线程负责执行main()方法。 在main()方法中再创建的线程,就称为主线程中的线程
。
如果main()方法中创建了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源
,main()方法即使执行完最后的语句,JVM也不会结束我们的程序,JVM一直要等到主线程中的所有线程都结束之后,才结束我们的Java应用程序。
线程的生命周期 Thread类或其子类创建的对象称作线程
新建
运行
线程必须调用start()方法
(从父类继承的方法)通知JVM,则JVM就知道有一个新的线程排队等候切换
当JVM将CPU使用权切换给线程时,线程是Thread类的子类创建的,则该类中的run()方法
就立刻执行。所以我们必须在子类中重写(override)父类的run()方法。注:Thread类中的run()方法没有具体内容。
在线程没有结束run()方法之前,不要让线程再调用start()方法,否则将发生IllegalThreadStateException异常。
中断 4种原因:
JVM将CPU资源从当前线程切换给其他线程,使本线程让出CPU的使用权,进而处于中断状态。
线程使用CPU资源期间,执行了sleep(int millsecond)
方法,使当前线程进入休眠状态。
线程使用CPU资源期间,执行了wait()
方法,使得当前线程进入中断(等待)状态。 等待状态的线程不会主动进到线程队列中排队等待CPU资源,必须由其他线程调用notify()
方法通知它,使得它重新进到线程队列中排队等待CPU资源,以便从中断处继续运行。
线程使用CPU资源期间,执行某个操作进入中断(阻塞)状态,比如执行读/写操作引起阻塞。 进入阻塞状态时线程不能进入排队队列,只有当引起阻塞的原因消除时,线程才重新进到线程队列中排队等待CPU资源,以便从原来中断处开始继续运行。
死亡 处于死亡状态的线程不具有继续运行的能力。线程释放了实体,即释放了分配给线程对象的内存. 线程死亡的原因:
正常运行的线程完成了它的全部工作,即执行完run()方法中的全部语句,结束了run()方法。
线程被提前强制终止,即强制run()方法结束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 class WriteWordThread extends Thread { WriteWordThread(String s) { setName(s); } public void run () { for (int i=1 ; i<=3 ;i++) System.out.println("Thread: " + getName()); } } public class Example8_1 { public static void main (String args[]) { WriteWordThread zhang, wang; zhang = new WriteWordThread ("Zhang" ); wang = new WriteWordThread ("Wang" ); zhang.start(); for (int i=1 ; i<=3 ; i++) { System.out.println("Main Thread" ); } wang.start(); } } class WriteWordThread extends Thread { int n = 0 ; WriteWordThread(String s, int n) { setName(s); this .n = n; } public void run () { for (int i=1 ; i<=3 ; i++) { System.out.println("Thread: " + getName()); try { sleep(n); } catch (InterruptedException e) {} } } } public class Example8_2 { public static void main (String args[]) { WriteWordThread zhang, wang; zhang = new WriteWordThread ("Zhang" , 200 ); wang = new WriteWordThread ("Wang" , 100 ); zhang.start(); wang.start(); } }
线程的优先级与调度管理
JVM中的线程调度器 负责管理线程,调度器把线程的优先级分为10个级别 ,分别用Thread类中的类静态常量表示。每个Java线程的优先级都在常数1(Thread.MIN_PRIORITY)到常数10(Thread.MAX_PRIORITY)的范围内。
如果没有明确设置线程的优先级,每个线程的优先级都为常数5(Thread.NORM_PRIORITY)
线程的优先级可以通过setPriority(int grade)
方法调整,这一方法需要一个int类型参数。如果此参数不在1-10的范围内,那么setPriority便产生一个lllegalArgumentException
异常。
getPriority方法返回线程的优先级。需要注意是,有些操作系统只能识别3个级别:1、5和10。
JVM中的线程调度器使高优先级的线程能有更高的概率运行。
Thread的子类创建线程 继承Thread类,重写父类的run()
方法 主线程使用exit(int n)
方法结束整个程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class Left extends Thread { int n = 0 ; public void run () { while (true ) { n++; System.out.println(n+"Left" ); try { sleep((int )(Math.random()*100 )); } catch (InterruptedException e) {} } } } class Right extends Thread { int n = 0 ; public void run () { while (true ) { n++; System.out.println(n+"Right" ); try { sleep((int )(Math.random()*100 )); } catch (InterruptedException e){} } } } public class Example8_3 { public static void main (String args[]) { Left left = new Left (); Right right = new Right (); left.start(); right.start(); while (true ) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } if (left.n>=8 || right.n>=8 ) { System.out.println(left.n + "," + right.n); System.exit(0 ); } } } }
Runnable接口 Runnable接口与目标对象 创建线程的另一个途径就是用Thread类直接创建线程对象Thread(Runnable task)
实现Runnable接口的类的实例对象task 称作所创建线程的目标对象target ,当线程调用start()
方法后,一旦轮到它来享用CPU资源,目标对象就会自动调用接口中的run()方法
(接口回调)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class TaskBank implements Runnable { private int money = 0 ; String name1,name2; TaskBank(String s1, String s2){ name1 = s1; name2 = s2; } public void setMoney (int mount) { money = mount; } public void run () { while (true ) { money = money-10 ; if (Thread.currentThread().getName().equals(name1)) { System.out.println(name1 + ": " + money); if (money<=100 ) { System.out.println(name1 + ": Finished" ); return ; } } else if (Thread.currentThread().getName().equals(name2)) { System.out.println(name2 + ": " + money); if (money<=60 ) { System.out.println(name2 + ": Finished" ); return ; } } try { Thread.sleep(800 ); } catch (InterruptedException e) {} } } } public class Example8_4 { public static void main (String args[]) { String s1="treasurer zhang" ; String s2="cashier cheng" ; TaskBank taskBank = new TaskBank (s1,s2); taskBank.setMoney(120 ); Thread zhang; Thread cheng; zhang = new Thread (taskBank); cheng = new Thread (taskBank); zhang.setName(s1); cheng.setName(s2); zhang.start(); cheng.start(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class Task implements Runnable { private int number = 0 ; public void setNumber (int n) { number = n; } public void run () { while (true ) { if (Thread.currentThread().getName().equals("add" )) { number++; System.out.printf("%d\n" ,number); } if (Thread.currentThread().getName().equals("sub" )) { number--; System.out.printf("%12d\n" ,number); } try { Thread.sleep(1000 ); } catch (InterruptedException e) {} } } } public class Example8_5 { public static void main (String args[]) { Task taskAdd = new Task (); taskAdd.setNumber(10 ); Task taskSub = new Task (); taskSub.setNumber(-10 ); Thread threadA,threadB,threadC,threadD; threadA = new Thread (taskAdd); threadB = new Thread (taskAdd); threadA.setName("add" ); threadB.setName("add" ); threadC = new Thread (taskSub); threadD = new Thread (taskSub); threadC.setName("sub" ); threadD.setName("sub" ); threadA.start(); threadB.start(); threadC.start(); threadD.start(); } }
关于run()方法中的局部变量 不同线程的run()方法中的局部变量互不干扰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class TaskAddSub implements Runnable { String s1,s2; TaskAddSub(String s1,String s2){this .s1=s1; this .s2=s2;} public void run () { int i=0 ; while (true ) { if (Thread.currentThread().getName().equals(s1)) { i=i+1 ; System.out.println(s1 + ":" + i); if (i>=4 ) { System.out.println(s1 + "Finished" ); return ; } } else if (Thread.currentThread().getName().equals(s2)) { i=i-1 ; System.out.println(s2 + ":" + i); if (i<=-4 ) { System.out.println(s2 + "Finished" ); return ; } } try { Thread.sleep(800 ); } catch (InterruptedException e) {} } } } public class Example8_6 { public static void main (String args[]) { String s1 = "ZHANG San" ; String s2 = "LI Si" ; TaskAddSub taskAddSub = new TaskAddSub (s1,s2); Thread zhang, li; zhang = new Thread (taskAddSub); li = new Thread (taskAddSub); zhang.setName(s1); li.setName(s2); zhang.start(); li.start(); } }
线程的常用方法 start()
启动线程run()
Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作。系统自动调用而用户程序不可以调用.sleep(int millsecond)
休眠isAlive()
线程的run()方法结束前/没有进入死亡状态前/未调用start()方法前,线程调用isAlive()方法返回true。线程进入死亡状态后(实体内存被释放),线程仍可以调用方法isAlive(),返回的值是false。一个已经运行的线程在没有进入死亡状态前,不要再给线程分配实体 currentThread()
返回当前正在使用CPU资源的线程interrupt()
用来“吵醒”休眠的线程. 当一些线程调用sleep()方法处于休眠状态时,一个使用CPU资源的其它线程在执行过程中,可以让休眠的线程分别调用interrupt()方法“吵醒”自己,即导致休眠的线程发生InterruptedException异常,从而结束休眠,重新排队等待CPU资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class TaskClassRoom implements Runnable { Thread teacher, zhang, li; TaskClassRoom() { teacher = new Thread (this ); zhang = new Thread (this ); li = new Thread (this ); zhang.setName("Zhang" ); li.setName("Li" ); teacher.setName("Pan" ); } public void run () { Thread thread = Thread.currentThread(); if (thread==zhang || thread==li) { try { System.out.println(thread.getName() + ": Sleep for 10s" ); Thread.sleep(10000 ); } catch (InterruptedException e) { System.out.println(thread.getName() + ": been wake up" ); } System.out.println(thread.getName() + ": Good morning" ); } else if (thread==teacher) { for (int i=1 ;i<=3 ;i++) { System.out.println(thread.getName() + ": Let's start ..." ); try { Thread.sleep(500 ); } catch (InterruptedException e) {} } zhang.interrupt(); li.interrupt(); } } } public class Example8_8 { public static void main (String args[]) { TaskClassRoom taskClassRoom = new TaskClassRoom (); taskClassRoom.zhang.start(); taskClassRoom.li.start(); taskClassRoom.teacher.start(); } }
线程同步 多个线程要执行一个synchronized
修饰的方法
线程A在占有CPU资源期间,调用执行synchronized方法, 那么在synchronized方法返回前(即synchronized方法调用执行完毕之前), 其他占有CPU资源的线程一旦调用这个synchronized方法就会引起堵塞 , 堵塞的线程一直要等到堵塞的原因消除( 即synchronized方法返回),再排队等待CPU资源,以便使用这个同步方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Bank implements Runnable { int money = 300 ; String treasurerName, cashierName; public Bank (String s1,String s2) { treasurerName=s1; cashierName=s2; } public void run () { saveOrTake(30 ); } public synchronized void saveOrTake (int number) { if (Thread.currentThread().getName().equals(treasurerName)) { for (int i=1 ;i<=3 ;i++) { money = money + number; try { Thread.sleep(1000 ); } catch (InterruptedException e) {} System.out.println(treasurerName + " : " + money); } } else if (Thread.currentThread().getName().equals(cashierName)) { for (int i=1 ;i<=2 ;i++) { money = money-number/2 ; try { Thread.sleep(1000 );} catch (InterruptedException e){} System.out.println(cashierName + " : " + money); } } } } public class Example8_9 { public static void main (String args[]) { String treasurerName = "Treaurer" , cashierName = "Cashier" ; Bank bank = new Bank (treasurerName, cashierName); Thread treasurer, cashier; treasurer = new Thread (bank); cashier = new Thread (bank); treasurer.setName(treasurerName); cashier.setName(cashierName); treasurer.start(); cashier.start(); } }
使用wait(),notify(),notifyAll()协调同步线程 wait(), notify()和notifyAll()都是Object类中的final方法,是被所有的类继承、且不允许重写 的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 class TicketSeller { int fiveNumber=1 , tenNumber=0 , twentyNumber=0 ; public synchronized void sellTicket (int receiveMoney) { String s=Thread.currentThread().getName(); if (receiveMoney==5 ) { fiveNumber = fiveNumber+1 ; System.out.println(s + " gives $5 to seller, seller gives " + s + " a ticket" ); } else if (receiveMoney==10 ){ while (fiveNumber<1 ){ try { System.out.println(s + " gives $10 to seller" ); System.out.println("seller asks " + s + " to wait" ); wait(); System.out.println(s + " stops waiting and starts to buy..." ); } catch (InterruptedException e){} } fiveNumber=fiveNumber-1 ; tenNumber=tenNumber+1 ; System.out.println(s + " gives $10 to seller, seller gives " + s + " a ticket and $5" ); } else if (receiveMoney==20 ){ while (fiveNumber<1 ||tenNumber<1 ){ try { System.out.println(s + " gives $20 to seller" ); System.out.println("seller asks " + s + " to wait" ); wait(); System.out.println(s+" stops waiting and starts to buy ..." ); } catch (InterruptedException e){} } fiveNumber = fiveNumber-1 ; tenNumber = tenNumber-1 ; twentyNumber = twentyNumber+1 ; System.out.println(s + " gives $20 to seller, seller gives " + s + " a ticket and $15" ); } notifyAll(); } } class Cinema implements Runnable { TicketSeller seller; String name1, name2, name3; Cinema(String s1,String s2,String s3) { seller = new TicketSeller (); name1 = s1; name2 = s2; name3 = s3; } public void run () { if (Thread.currentThread().getName().equals(name1)) { seller.sellTicket(20 ); } else if (Thread.currentThread().getName().equals(name2)) { seller.sellTicket(10 ); } else if (Thread.currentThread().getName().equals(name3)) { seller.sellTicket(5 ); } } } public class Example8_10 { public static void main (String args[]) { String s1="Zhang" , s2="Sun" , s3="Zhao" ; Cinema cinema = new Cinema (s1,s2,s3); Thread zhang, sun, zhao; zhang = new Thread (cinema); sun = new Thread (cinema); zhao = new Thread (cinema); zhang.setName(s1); sun.setName(s2); zhao.setName(s3); zhang.start(); sun.start(); zhao.start(); } }
挂起、恢复和终止线程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class A implements Runnable { int number = 0 ; volatile boolean stop = false ; boolean getStop () { return stop; } public void run () { while (true ) { number++; System.out.println(Thread.currentThread().getName() + " : " + number); if (number==3 ) { try { System.out.println(Thread.currentThread().getName() + " : hang up" ); stop = true ; hangUP(); System.out.println(Thread.currentThread().getName() + " : resumed" ); } catch (Exception e){} } try { Thread.sleep(1000 ); } catch (Exception e){} } } public synchronized void hangUP () throws InterruptedException{ wait(); } public synchronized void restart () { notifyAll(); } } public class Example8_11 { public static void main (String args[]) { A target = new A (); Thread thread = new Thread (target); thread.setName("Zhang San" ); thread.start(); while (target.getStop()==false ) { try { Thread.sleep(1000 ); } catch (Exception e){} } System.out.println("Main Thread" ); target.restart(); } }
线程联合
一个线程A在占有CPU资源期间,可以让线程B调用join()方法和本线程联合 如:B.join();
我们称A在运行期间联合了B。
线程A在占有CPU资源期间联合B线程,则A线程立刻中断执行,等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源,以便恢复执行。 如果A线程准备联合的B线程已经结束,那么B.join()不会产生任何效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class JoinThread implements Runnable { Thread threadA, threadB; String content[] = {"今天晚上," , "大家不要" , "回去的太早," , "还有工作" , "需要大家做!" }; JoinThread() { threadA=new Thread (this ); threadB=new Thread (this ); threadB.setName("经理" ); } public void run () { if (Thread.currentThread()==threadA) { System.out.println("我等" +threadB.getName()+"说完再说话" ); threadB.start(); while (threadB.isAlive()==false ){} try { threadB.join(); } catch (InterruptedException e){} System.out.printf("\n我开始说话:\"我明白你的意思了,谢谢\"" ); } else if (Thread.currentThread()==threadB) { System.out.println(threadB.getName()+"说:" ); for (int i=0 ;i<content.length;i++) { System.out.print(content[i]); try { threadB.sleep(1000 ); } catch (InterruptedException e){} } } } } public class Example8_13 { public static void main (String args[]) { JoinThread a = new JoinThread (); a.threadA.start(); } }
守护线程
一个线程调用void setDaemon(boolean on)
方法可以将自己设置成一个守护(daemon)线程,例如:thread.setDaemon(true);
线程默认是非守护线程,非守护线程也称作用户(user)线程
当程序中的所有用户线程都已结束运行时,即使守护线程的run()方法中还有需要执行的语句,守护线程也立刻结束运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class TaskDaemon implements Runnable { Thread A,B; TaskDaemon() { A = new Thread (this ); B = new Thread (this ); } public void run () { if (Thread.currentThread()==A) { for (int i=0 ;i<3 ;i++) { System.out.println("i=" +i) ; try { Thread.sleep(1000 ); } catch (InterruptedException e){} } } else if (Thread.currentThread()==B) { while (true ) { System.out.println("线程B是守护线程 " ); try { Thread.sleep(1000 ); } catch (InterruptedException e){} } } } } public class Example8_14 { public static void main (String args[]) { TaskDaemon a=new TaskDaemon (); a.A.start(); a.B.setDaemon(true ); a.B.start(); } }
线程池 thread pool an ideal way to manage the number of tasks executing concurrently. 管理并发执行的任务Executor 接口用于执行线程池中的任务,ExecutorService 是 Executor 的一个子接口,用于管理和控制任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 class PrintChar implements Runnable { private char charToPrint; private int times; public PrintChar (char c, int t) { charToPrint = c; times = t; } @Override public void run () { for (int i = 0 ; i < times; i++) { System.out.print(charToPrint); } } } class PrintNum implements Runnable { private int lastNum; public PrintNum (int n) { lastNum = n; } @Override public void run () { for (int i = 1 ; i <= lastNum; i++) { System.out.print(" " + i); } } } public class TaskThreadDemo { public static void main (String[] args) { Runnable printA = new PrintChar ('a' , 100 ); Runnable printB = new PrintChar ('b' , 100 ); Runnable print100 = new PrintNum (100 ); Thread thread1 = new Thread (printA); Thread thread2 = new Thread (printB); Thread thread3 = new Thread (print100); thread1.start(); thread2.start(); thread3.start(); } } import java.util.concurrent.*;public class ExecutorDemo { public static void main (String[] args) { ExecutorService executor= Executors.newFixedThreadPool(3 ); executor.execute(new PrintChar ('a' , 100 )); executor.execute(new PrintChar ('b' , 100 )); executor.execute(new PrintNum ( 100 )); executor.shutdown(); } }
锁->线程同步 Synchronization Using Locks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import java.util.concurrent.*;import java.util.concurrent.locks.*;public class AccountWithSyncUsingLock { private static Account account = new Account (); public static void main (String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0 ; i < 100 ; i++) { executor.execute(new AddAPennyTask ()); } executor.shutdown(); while (!executor.isTerminated()) {} System.out.println("what is balance?" + account.getBalance()); } public static class AddAPennyTask implements Runnable { public void run () { account.deposit(1 ); } } private static class Account { private static Lock lock = new ReentrantLock (); private int balance = 0 ; public int getBalance () { return balance; } public void deposit (int amount) { lock.lock(); try { int newBalance = balance + amount; Thread.sleep(5 ); balance = newBalance; } catch (InterruptedException ex) { } finally { lock.unlock(); } } } }
线程合作 Cooperation among Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 import java.util.concurrent.*;import java.util.concurrent.locks.*;public class ThreadCooperation { private static Account account = new Account (); public static void main (String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2 ); executor.execute(new DepositTask ()); executor.execute(new WithdrawTask ()); executor.shutdown(); } public static class DepositTask implements Runnable { @Override public void run () { try { while (true ){ account.deposit((int )(Math.random()*10 )+1 ); Thread.sleep(1000 ); } } catch (InterruptedException ex){ ex.printStackTrace(); } } } public static class WithdrawTask implements Runnable { @Override public void run () { while (true ){ account.withdraw((int )(Math.random()*10 )+1 ); } } } private static class Account { private static Lock lock = new ReentrantLock (); private static Condition newDeposit = lock.newCondition(); private int balance; public int getBalance () { return balance; } public void withdraw (int amount) { lock.lock(); try { while (balance<amount){ System.out.println("\t\tWaiting for deposit" ); newDeposit.await(); } balance -= amount; System.out.println("\t\tWithdraw " + amount+"\t\t" +getBalance()); } catch (InterruptedException ex){ ex.printStackTrace(); } finally { lock.unlock(); } } public void deposit (int amount) { lock.lock(); try { balance += amount; System.out.println("\t\tDeposit " + amount+"\t\t\t\t\t" +getBalance()); newDeposit.signalAll(); } finally { lock.unlock(); } } } }