1 package day2_4; 2 3 /** 4 *例子:创建三个窗口卖票,总票数为100张,使用实现Runnable接口 5 * 1.问题:卖票过程中,出现了重票、错票的情况 --->出现了线程安全问题 6 * 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票 7 * 3.如何解决:当一个线程A在操作ticket时,其他线程不能参与进来,直到线程A操作完(即使A出现阻塞),其他线程才可以开始 8 * 才做操作ticket 9 * 4.在Java中我们通过同步机制,来解决线程的安全问题 10 * 11 * 方式一:同步代码块 12 * 13 * synchronized(同步监视器){ 14 * //需要被同步的代码 15 * } 16 * 17 * 说明:1.操作共享数据的代码,就是需要被同步的代码 -->不能包含代码少了,也不能包含代码多了(1.可以会改变逻辑 2.效率变低) 18 * 2.共享数据:多个线程共同操作的变量,比如ticket就是共享数据 19 * 3.同步监视器:俗称锁。任何一个类的对象都可以充当锁 20 * 要求:多个线程必须共用同一把锁(也就是多个线程共享的一个对象) 21 * 22 * 补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this来充当同步监视器 23 * 说明:但是在继承Thread类创建多线程的方式中,慎用this充当同步监视器,可以考虑使用 24 * 线程类的类对象充当同步监视器 25 * 26 * @Author Tianhao 27 * @create 2021-02-04-21:31 28 */ 29 30 class Window4 extends Thread { 31 //加上static保证多个线程共享 32 private static int ticket = 100; 33 //加上static保证多个线程共享 34 private static Object obj = new Object(); 35 36 @Override 37 public void run() { 38 while (true) { 39 //错误的 40 //synchronized(this){ //this 表示w1,w2,w3,不是这三个线程共享的对象,所以不能充当同步监视器 41 //正确的 42 //synchronized (obj) { 43 synchronized(Window4.class){ // Class clazz = Window4.class 每个类的类对象是唯一的 44 if (ticket > 0) { 45 try { 46 sleep(100); 47 } catch (InterruptedException e) { 48 e.printStackTrace(); 49 } 50 System.out.println(getName() + "卖票,票号:" + ticket); 51 ticket--; 52 } else { 53 break; 54 } 55 } 56 } 57 } 58 } 59 60 public class WindowTest4 { 61 public static void main(String[] args) { 62 Window4 w1 = new Window4(); 63 Window4 w2 = new Window4(); 64 Window4 w3 = new Window4(); 65 w1.setName("窗口1"); 66 w2.setName("窗口2"); 67 w3.setName("窗口3"); 68 w1.start(); 69 w2.start(); 70 w3.start(); 71 } 72 }