上海旅游网站建设,查看服务器上的网站,wordpress常用主题,重庆网站设计系统day31上
线程安全 – 加锁 注意#xff1a;要想多个线程互斥住#xff0c;就必须使用同一把锁(对象)#xff01;#xff01;#xff01; 加锁方式 synchronized Lock synchronized 继day30的售票需求案例学习 学习思路#xff1a; 1.使用线程类、任务类方式不同 2.加锁方…day31上
线程安全 – 加锁 注意要想多个线程互斥住就必须使用同一把锁(对象) 加锁方式 synchronized Lock synchronized 继day30的售票需求案例学习 学习思路 1.使用线程类、任务类方式不同 2.加锁方式不同 3.对于加锁中同步代码块、同步方法不同 同步代码块 synchronized(锁对象){//自动上锁 …想要互斥的代码… }//自动解锁 见day30 同步方法 同步方法 – 成员同步方法 注意锁对象 - this原因成员方法属于对象 public synchronized void method(){//自动上锁 …想要互斥的代码… }//自动解锁 同步方法 – 静态同步方法 注意锁对象 - 类.class原因静态方法属于类 public static synchronized void method(){//自动上锁 …想要互斥的代码… }//自动解锁 Lock 补充 Doug Lea道格·利编写的util.concurrent包 个人开发线程安全 //锁对象 Lock lock new ReentrantLock(); lock.lock();//手动上锁 …想要互斥的代码… lock.unlock();//手动解锁 需求 铁道部发布了一个售票任务要求销售1000张票要求有3个窗口来进行销售请编写多线程程序来模拟这个效果该题涉及到线程安全https://www.jb51.net/article/221008.htm i. 窗口001正在销售第1张票 ii. 窗口001正在销售第2张票 iii. 窗口002正在销售第3张票 iv. 。。。 v. 窗口002正在销售第1000张票 涉及到线程安全要加锁 使用线程类解决需求
synchronized方式
使用同步代码块 继day30 使用同步方法
public class MyThread extends Thread{private static int allTicket 1000;private static int curTicket 0;public MyThread(String name) {super(name);}Overridepublic void run() {while(curTicket allTicket){method();}}//锁对象MyThread.classpublic static synchronized void method(){if(curTicket allTicket){curTicket;System.out.println(窗口 Thread.currentThread().getName() 正在销售第 curTicket 张票);}if(curTicket allTicket){System.out.println(窗口 Thread.currentThread().getName() 票已经售完);}}}public class Test01 {public static void main(String[] args) {MyThread t1 new MyThread(001);MyThread t2 new MyThread(002);MyThread t3 new MyThread(003);t1.start();t2.start();t3.start();}
}方法外面加锁还是锁不住 原因锁对象 - this原因成员方法属于对象new了三个对象就有三把锁对象锁不住 解决再把同步方法设置成静态变成一个锁对象就能锁锁上 Lock方式
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyThread extends Thread{private static int allTicket 1000;private static int curTicket 0;private static Lock lock new ReentrantLock();public MyThread(String name) {super(name);}Overridepublic void run() {while(curTicket allTicket){lock.lock();//手动上锁try {if(curTicket allTicket){curTicket;System.out.println(窗口 Thread.currentThread().getName() 正在销售第 curTicket 张票);}if(curTicket allTicket){System.out.println(窗口 Thread.currentThread().getName() 票已经售完);}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();//手动解锁}}}
}run()中new了锁对象添加了手动上锁和手动解锁还是锁不住 原因线程new了三个对象都调用run方法就有三把锁对象锁不住 解决把new的锁放在run方法外面再把new的锁对象设置成静态变成一个锁对象就能锁锁上 注意 考虑到想要互斥的代码有可能出现异常如果出现异常就解不了锁锁就用不了用trycatch处理鼠标右键Surround With保证能解锁下一次线程使用 使用任务类解决需求
synchronized方式
使用同步代码块
public class Task implements Runnable{private int allTicket 1000;private int curTicket 0;Overridepublic void run() {while(curTicket allTicket){synchronized (this) {if(curTicket allTicket){curTicket;System.out.println(窗口 Thread.currentThread().getName() 正在销售第 curTicket 张票);}}}System.out.println(窗口 Thread.currentThread().getName() 票已售完);}}public class Test01 {public static void main(String[] args) {Task task new Task();Thread t1 new Thread(task, 001);Thread t2 new Thread(task, 002);Thread t3 new Thread(task, 003);t1.start();t2.start();t3.start();}
}代码实现出现的问题 与day30中的不太一样day30要求是不会出现脏数据而现在是要保证锁对象用得好 问题一 三个窗口各卖1000张票一共卖了3000张 出现原因三个线程抢到CPU资源后都会调用run方法curTicket和allTicket都是run方法里的局部变量所以会调用3次 解决思路curTicket和allTicket设置为成员属性三个线程共用同一个任务 注意 设置成静态属性和成员属性的区别设置成成员属性对于”铁道部发布了一个售票任务“设置成静态没有问题但考虑到多个售票任务静态对象就不好售票任务之间是不同的 问题二 有些票没有卖有些票卖了重票 出现原因当前线程抢到CPU资源后做了票的自增但是还没来得及输出时间片到了就退出CPU资源然后其他线程抢到CPU资源了 解决方案当前线程抢到CPU资源后票的自增和输出执行完毕才能切换到其他线程运行 – 加锁 注意 对于锁对象问题1提到静态的是不好的所以使用非静态的 通常用this原因是this表当前任务的对象对于外部有多个任务时就会针对不同任务相应互斥内容进行互斥 问题三 多卖了票 出现原因curTicket到了临界点999三个线程都可以进判断然后上锁 解决方案在锁中再次判断 注意 1.对于两个判断为什么不写出if-else的原因如果写出if-elseif正常执行不会再执行else就会有一个售完票的窗口输出不了“窗口xxx票已售完” 2.对于也不写成双if判断把售完的判断不加锁的原因以前的代码是存在问题的有可能正好最后一个票卖完解锁下一次curTicket不小于allTicket就进不去了也没办法执行判断卖完的输出 使用同步方法 使用成员属性的原因同上 public class Task implements Runnable{private int allTicket 1000;private int curTicket 0;Overridepublic void run() {while(curTicket allTicket){method();}System.out.println(窗口 Thread.currentThread().getName() 票已售完);}public synchronized void method(){if(curTicket allTicket){curTicket;System.out.println(窗口 Thread.currentThread().getName() 正在销售第 curTicket 张票);}}}Lock方式 加锁参考使用线程类解决需求的lock方式lock注意trycatch 小结 线程类方式和任务类方式的区别线程类方式不灵活任务类是新建的任务交给线程更灵活后续普遍使用任务类方式 设置成静态属性和成员属性的区别设置成成员属性对于”铁道部发布了一个售票任务“设置成静态没有问题但考虑到多个售票任务静态对象就不好售票任务之间是不同的 总结 1.线程安全 — 买票案例 synchronized代码块 synchronized方法成员同步方法、静态同步方法 Lock锁 注意 1.加锁的方式 2.锁对象多个线程去操作同一把锁才能互斥住