1.传统方式1
一个NumberHolder2类
package com.thread.comm; public class NumberHolder2 { private int number; public synchronized void increase() { try { for(int i=0;i<1000;i++){ if (0 != number){ System.out.println(Thread.currentThread().getName()+"----"+ i +"被阻塞"+ number); wait(); }else{ // 能执行到这里说明已经被唤醒 // 并且number为0 number++; System.out.println(Thread.currentThread().getName()+"----"+ i +"----"+ number); // 通知在等待的线程 notifyAll(); } } } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void decrease() { try { for(int i =0 ;i<100;i++){ if (0 == number){ System.out.println(Thread.currentThread().getName()+"----"+ i +"被阻塞"+ number); wait(); }else{ // 能执行到这里说明已经被唤醒 // 并且number不为0 number--; System.out.println(Thread.currentThread().getName()+"----"+ i +"----"+ number); notifyAll(); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
两个操作线程
package com.thread.comm; public class IncreaseThread extends Thread{ private NumberHolder2 numberHolder; public IncreaseThread(String name,NumberHolder2 numberHolder) { super(name); this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行增加操作 numberHolder.increase(); } } }
package com.thread.comm; public class DecreaseThread extends Thread { private NumberHolder2 numberHolder; public DecreaseThread(String name,NumberHolder2 numberHolder) { super(name); this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行减少操作 numberHolder.decrease(); } } }
执行
package com.thread.comm; public class NumberTest { public static void main(String[] args) { NumberHolder2 numberHolder = new NumberHolder2(); new IncreaseThread("加1-1",numberHolder).start(); new DecreaseThread("减2-1",numberHolder).start(); new DecreaseThread("减2-2",numberHolder).start(); } }
运行结果
。。。 减2-2----98被阻塞0 加1-1----192----1 加1-1----193被阻塞1 减2-2----99----0 减2-1----92被阻塞0 加1-1----194----1 加1-1----195被阻塞1 减2-1----93----0 减2-1----94被阻塞0 加1-1----196----1 加1-1----197被阻塞1 减2-1----95----0 减2-1----96被阻塞0 加1-1----198----1 加1-1----199被阻塞1 减2-1----97----0 减2-1----98被阻塞0 加1-1----200----1 加1-1----201被阻塞1 减2-1----99----0 加1-1----202----1 加1-1----203被阻塞1
从结果上可以验证出 线程执行存在随机性。
1.如果是一增加一减少两条线程,也可能出现一个线程进程先死亡,导致另外一个线程没有被唤醒,导致整个进程一致处于阻塞状态。
2.一定情况下可以使用wait(1000),通过时间设定,使得处于阻塞状态的线程进入就绪状态,从而保证整个进程执行完成。例如可以将NumberHolder2中的wait()改成wait(1000).
2.传统通讯2---在同一个账户中有多个线程进行存钱和取钱
account类
package com.thread.communication.tradition; public class Account { private String accountNo; private double balance; private boolean flag =false; public Account(){} public Account(String accountNo , double balance){ this.accountNo=accountNo; this.balance=balance; } public void setAccountNo(String num){ this.accountNo=num; } public String getAccountNo(){ return this.accountNo; } public double getBalance(){ return this.balance; } public synchronized void draw(double drawAmount){ try{ if(!flag){ wait(); }else{ System.out.println(Thread.currentThread().getName() + "取钱: " + drawAmount); this.balance-=drawAmount; System.out.println("当前余额是: "+ balance); flag = false; notifyAll(); } }catch(InterruptedException ex){ ex.printStackTrace(); } } public synchronized void deposit(double depositAmount){ try{ System.out.println("开始存钱"); if(flag){ wait(); }else{ System.out.println(Thread.currentThread().getName() + "存钱: " + depositAmount); this.balance+=depositAmount; System.out.println("当前余额是: "+ balance); flag = true; notifyAll(); } }catch(InterruptedException ex){ ex.printStackTrace(); } } public int hashCode(){ return accountNo.hashCode(); } public boolean equals(Object obj){ if(this == obj) return true; if(obj !=null && obj.getClass()==Account.class){ Account target =(Account)obj; return target.getAccountNo().equals(accountNo); } return false; } }
两个线程类
package com.thread.communication.tradition; public class DepositThread extends Thread{ private Account account; private double depositAmount; public DepositThread(String name,Account account,double depositAmount){ super(name); this.account=account; this.depositAmount=depositAmount; } public void run(){ for (int i=0;i<100;i++){ account.deposit(depositAmount); } } }
package com.thread.communication.tradition; public class DrawThread extends Thread{ private Account account; private double drawAmount; public DrawThread(String name,Account account,double drawAmount){ super(name); this.account=account; this.drawAmount=drawAmount; } public void run(){ for (int i=0;i<100;i++){ account.draw(drawAmount); } } }
测试类
package com.thread.communication.tradition; public class DrawTest { public static void main(String[] args) { Account acct = new Account("account1",0.0); System.out.println(acct.getAccountNo() + " " + acct.getBalance()); new DepositThread("存钱者甲",acct,800.0).start(); new DepositThread("存钱者已",acct,800.0).start(); new DepositThread("存钱者丙",acct,800.0).start(); new DrawThread("取钱者",acct,800.0).start(); } }