java 多线程之synchronized wait/notify解决买票问题
一.Java线程具有五中基本状态
新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
二. Java多线程的创建及启动
1.继承Thread类,重写该类的run()方法。
两个线程同时运行,随机产生4位随机字符
1 import java.util.Random; 2 3 public class 多线程 { 4 5 public static Object lock = new Object(); 6 7 public static void randomString() { 8 String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 9 Random random = new Random(); 10 StringBuffer sb = new StringBuffer(); 11 for (int i = 0; i < 4; i++) { 12 int number = random.nextInt(62); 13 sb.append(str.charAt(number)); 14 } 15 System.out.print(sb); 16 } 17 18 public static void main(String[] args) { 19 20 new Thread(new myTh1()).start(); 21 new Thread(new myTh2()).start(); 22 23 } 24 25 } 26 27 class myTh1 extends Thread { 28 @Override 29 public void run() { 30 while (true) { 31 32 try { 33 synchronized (多线程.lock) { 34 多线程.randomString(); 35 System.out.print("------"+Thread.currentThread().getName()); 36 System.out.println(); 37 } 38 sleep(1000); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 } 43 } 44 } 45 46 class myTh2 extends Thread { 47 @Override 48 public void run() { 49 while (true) { 50 try { 51 synchronized (多线程.lock) { 52 多线程.randomString(); 53 System.out.print("------"+Thread.currentThread().getName()); 54 System.out.println(); 55 } 56 sleep(1000); 57 } catch (InterruptedException e) { 58 e.printStackTrace(); 59 } 60 } 61 } 62 }
2.实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象
主线程和两个实现Runnable接口的线程同时运行,线程对象只运行5次。
1 public class 多线程Runnable { 2 3 public static void main(String[] args) { 4 System.out.println(Thread.currentThread().getName()); 5 try { 6 Thread.sleep(3000); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 11 new Thread(new myTh3()).start(); 12 new Thread(new myTh4()).start(); 13 14 15 } 16 } 17 class myTh3 extends Thread{ 18 int i=0; 19 @Override 20 public void run() { 21 while (i<5) { 22 System.out.println(Thread.currentThread().getName()); 23 try { 24 sleep(2000); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 i++; 29 } 30 31 } 32 33 } 34 35 class myTh4 implements Runnable{ 36 37 int i=0; 38 @Override 39 public void run() { 40 while (i<5) { 41 System.out.println(Thread.currentThread().getName()); 42 i++; 43 } 44 45 } 46 }
3.synchronized, wait, notify结合:
解决问题三个人去买票,张某有20元,李某10元。赵某5元。电影票5元一张,售货员只有3张5元的
1 /*问题: 2 * 三个人去买票,张某有20元,李某10元。赵某5元。 3 * 电影票5元一张,售货员只有3张5元的。 4 * 5 * 思路: 6 * 张某买了票就会少3张5元的 7 * 李某买了票就会少1张5元的 8 * 赵某买了票就会多1张5元的 9 * 所以有三种情况: 10 * 一。赵某先买,张李都可以买 11 * 二。张某先买,此时李某买不了,只能等待赵某买了,再买 12 * 三。李某先买,此时张某买不了,只能等待赵某买了,再买 13 * 14 * 静态常量:售货员总钱数 sum=3 15 * 16 * 1.创建三个线程分别为张某,李某,赵某 17 * 2.判断此时sum值,合适就买票,减去相应的钱数,不合适就等待。 18 */ 19 import java.util.ArrayList; 20 import java.util.Iterator; 21 import java.util.List; 22 23 public class 多线程3 { 24 25 public static int sum = 3;//设置零钱总张数为3张 26 public static Object look = new Object();//建立一个锁 27 28 public static List<Thread> arrayList = new ArrayList<>();//建立集合 保存这三个购买人的线程 29 30 public static void main(String[] args) throws InterruptedException { 31 //随机将赵某李某张某添加到集合中 32 arrayList.add(new li()); 33 arrayList.add(new zhang()); 34 arrayList.add(new zhao()); 35 36 //通过迭代器遍历集合 37 Iterator<Thread> iterator = arrayList.iterator(); 38 39 while (iterator.hasNext()) { 40 //获取线程 41 Thread t = iterator.next(); 42 //线程启动 43 t.start(); 44 //线程睡眠 45 t.sleep(2000); 46 } 47 48 } 49 } 50 /** 51 * 张某线程 52 * @author Administrator 53 * 54 */ 55 class zhang extends Thread { 56 @Override 57 public void run() { 58 //因为要判断等待和唤醒,并且操作sum,所以在此处加锁 59 synchronized (多线程3.look) { 60 while (多线程3.sum < 3) { 61 try { 62 System.out.println("因为此时零钱不足:"+多线程3.sum+"张"); 63 System.out.println("所以张某没买到电影票,等待购买"); 64 多线程3.look.wait(); 65 } catch (InterruptedException e) { 66 e.printStackTrace(); 67 } 68 } if (多线程3.sum > 2) { 69 多线程3.sum = 多线程3.sum - 3; 70 多线程3.look.notify(); 71 System.out.println("张某买到了电影票"); 72 System.out.println("此时零钱数为:"+多线程3.sum+"张"); 73 } 74 } 75 } 76 } 77 /** 78 * 李某线程 79 * @author Administrator 80 * 81 */ 82 class li extends Thread { 83 @Override 84 public void run() { 85 synchronized (多线程3.look) { 86 while (多线程3.sum < 1) { 87 try { 88 System.out.println("因为此时零钱不足:"+多线程3.sum+"张"); 89 System.out.println("所以李某没买到电影票,等待购买"); 90 多线程3.look.wait(); 91 } catch (InterruptedException e) { 92 e.printStackTrace(); 93 } 94 } if (多线程3.sum >= 1) { 95 多线程3.sum = 多线程3.sum - 1; 96 多线程3.look.notify(); 97 System.out.println("李某买到了电影票"); 98 System.out.println("此时零钱数为:"+多线程3.sum+"张"); 99 } 100 101 } 102 } 103 } 104 /** 105 * 赵某线程 106 * @author Administrator 107 * 108 */ 109 class zhao extends Thread { 110 @Override 111 public void run() { 112 synchronized (多线程3.look) { 113 if (多线程3.sum >= 0) { 114 多线程3.sum = 多线程3.sum + 1; 115 System.out.println("赵某买到了电影票"); 116 System.out.println("此时零钱数为:"+多线程3.sum+"张"); 117 多线程3.look.notify(); 118 } 119 } 120 } 121 }
全部都是培训课后习题,最后一个足足搞了半天,希望我写的没毛病,求指教。。谢谢大佬。
-------------------------------------------
新人只求记录学习生活!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!