⑦. 线程同步
①. 买票案例出现的两个问题
- ①. 出现的问题:①. 相同票数出现多次;②.出现了负票
- ②. 代码展示:
public class SellTicket implements Runnable { //定义一个成员变量表示有100张票 private int tickets=100; public void run(){ while (true){ if(tickets>0){ try { //通过sleep()方法来等待 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets--+"张票"); }else{ //System.out.println(""); } } } } @SuppressWarnings("all") public class SellTicketDemo { public static void main(String[] args) { SellTicket st = new SellTicket(); Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); t1.start(); t2.start(); t3.start(); } }
- ③. 原因分析:
- 为什么会出现相同的票
- 为什么会出现负票
②. 同步代码块synchronized
- ①. 为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)
是否有多线程坏境
是否有共享数据
是否有多条语句操作共享数据
②. 如何解决多线程安全问题
基本思想:让程序没有安全问题的坏境
把多条语句操作的共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可
③. 怎么锁起来呢?
synchronized(任意对象):相当于给代码加锁了,任意对象就可以看成是一把锁
④. 同步的好处和弊端
好处:解决了多线程的数据安全问题
弊端:当线程很多时,因为每个线程都会判断同步上的锁,这是很浪费资源的,无形中会降低程序的运行效率
public class SellTicket implements Runnable { //定义一个成员变量表示有100张票 private int tickets=100; private Object obj=new Object(); public void run(){ while (true){ //这里放的锁要是同一把锁才可以 synchronized(obj){ if(tickets>0){ try { //通过sleep()方法来等待 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets--+"张票"); }else{ //System.out.println(""); } } } } }
③. 同步方法
- ①. 同步方法:就是把synchronized 关键字加到方法上
同步方法的锁对象是什么呢? this
格式:修饰符 synchronized 返回值类型 方法名(方法参数){ }
private int tickets = 100; private Object obj = new Object(); private int x = 0; @Override public void run() { while (true) { if (x % 2 == 0) { // synchronized (obj) { synchronized (this) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } } else { sellTicket(); } x++; } } private synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } }
②. 同步静态方法:就是把synchronized关键字加到静态方法上
格式:修饰符 static synchronized 返回值类型 方法名(方法参数){ }
同步静态方法的锁对象是什么呢?
类名.class
public class SellTicket implements Runnable { private static int tickets = 100; private Object obj = new Object(); private int x = 0; @Override public void run() { while (true) { if (x % 2 == 0) { synchronized (SellTicket.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } } else { sellTicket(); } x++; } } private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } }