当前位置: 首页 > news >正文

网站排名推广joomla 做的网站

网站排名推广,joomla 做的网站,网站后台超链接怎么做,餐饮品牌全案策划文章目录 一、死锁#xff08;1#xff09;说明#xff08;2#xff09;案例1、案例12、案例23、案例3 #xff08;3#xff09;诱发死锁的原因及解决方案1、诱发死锁的原因2、避免死锁 二、JDK5.0新特性#xff1a;Lock(锁)#xff08;1#xff09;介绍#xff08;2… 文章目录 一、死锁1说明2案例1、案例12、案例23、案例3 3诱发死锁的原因及解决方案1、诱发死锁的原因2、避免死锁 二、JDK5.0新特性Lock(锁)1介绍2案例3synchronized与Lock的对比 一、死锁 1说明 不同的线程分别占用对方需要的同步资源不放弃都在等待对方放弃自己需要的同步资源就形成了线程的死锁。 比如线程1拿着同步监视器锁)它拿着锁1等着锁2但是线程2拿着锁2等着锁1。两个线程僵持着互相等待这就构成了死锁。 我们编写程序时要避免出现死锁。 一旦出现死锁整个程序既不会发生异常也不会给出任何提示只是所有线程处于阻塞状态无法继续。 2案例 1、案例1 StringBuilder跟字符串相关的类后边说这里看成字符串就可以了里面没有任何数据 用它造两个对象 public class DeadLockTest {public static void main(String[] args) {StringBuilder s1new StringBuilder();StringBuilder s2new StringBuilder();} }然后new一个线程 new Thread(){Overridepublic void run() {} }.start();线程里面调用了run方法把s1当作同步监视器锁然后用s1调用append方法用于添加添加一个“a”如下 new Thread(){Overridepublic void run() {synchronized (s1){s1.append(a); //理解为空字符串 a}} }.start();然后s2也添加一个“1”如下 new Thread(){Overridepublic void run() {synchronized (s1){s1.append(a);s2.append(1);}} }.start();将s2当作一个锁给s1添加一个“b”给s2添加一个“2”。如下 new Thread(){Overridepublic void run() {synchronized (s1){s1.append(a);s2.append(1);synchronized (s2){s1.append(b);s2.append(2);System.out.println(s1);System.out.println(s2);}}} }.start();然后在这里sleep睡一下便于演示死锁的问题 new Thread(){Overridepublic void run() {synchronized (s1){s1.append(a);s2.append(1);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s2){s1.append(b);s2.append(2);System.out.println(s1);System.out.println(s2);}}} }.start();说一下大致过程 线程1进入run获得锁s1然后稍微sleep一会醒来之后再拿着锁s2执行后面的操作执行结束后打印s1与s2。 现在我们再写一个线程原理与上面的类似只不过这个线程2先获得锁s2再获得锁s1如下 //线程2 new Thread(){Overridepublic void run() {synchronized (s2){s1.append(c);s2.append(3);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s1){s1.append(d);s2.append(4);System.out.println(s1);System.out.println(s2);}}} }.start();若此时没有sleep如下 public class DeadLockTest {public static void main(String[] args) {StringBuilder s1new StringBuilder();StringBuilder s2new StringBuilder();//线程1new Thread(){Overridepublic void run() {synchronized (s1){s1.append(a);s2.append(1);synchronized (s2){s1.append(b);s2.append(2);System.out.println(s1);System.out.println(s2);}}}}.start();//线程2new Thread(){Overridepublic void run() {synchronized (s2){s1.append(c);s2.append(3);synchronized (s1){s1.append(d);s2.append(4);System.out.println(s1);System.out.println(s2);}}}}.start();} }运行如下 可以发现并没有出现死锁这就是问题所在能执行成功不意味着这个程序没有问题。 其实它是存在问题的可能性的。 从输出结果上来看先执行的是线程1s1获得as2获得1然后s1获得bs2获得2。最终s1得到abs2得到12。 然后线程2执行在原有基础上又添加了数据最终s1得到abcds2得到1234。 也就是说线程1执行结束线程2才 开始执行。 当线程1执行结束的时候s1与s2两个同步监视器都被释放了所以线程2执行的时候才能顺利拿到s1与s2。 如果先执行的是第2个线程再执行第1个线程结果就是cd34cdab3412。 现在我们加上sleep让死锁的概率高一点注意这里只是让它出现的概率变高了并不是从无到有只是数量上的并不是质变。 代码 package yuyi04.lock;/*** ClassName: DeadLockTest* Package: yuyi04.lock* Description:** Author 雨翼轻尘* Create 2024/2/1 0001 15:18*/ public class DeadLockTest {public static void main(String[] args) {StringBuilder s1new StringBuilder();StringBuilder s2new StringBuilder();//线程1new Thread(){Overridepublic void run() {synchronized (s1){s1.append(a);s2.append(1);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s2){s1.append(b);s2.append(2);System.out.println(s1);System.out.println(s2);}}}}.start();//线程2new Thread(){Overridepublic void run() {synchronized (s2){s1.append(c);s2.append(3);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s1){s1.append(d);s2.append(4);System.out.println(s1);System.out.println(s2);}}}}.start();} }输出 可以看到出现了死锁。 线程1拿着同步监视器s1在sleep的时候线程2执行。 然后线程2拿着同步监视器s2往后执行也碰到了sleep。 线程1醒来之后去拿同步监视器s2但是s2在线程2手里。大家就僵持住了。 这就构成了死锁如下 2、案例2 案例1很容易看出来会出现死锁现在再来看一个例子 代码 package yuyi04.lock;/*** ClassName: DeadLock* Package: yuyi04.lock* Description:** Author 雨翼轻尘* Create 2024/2/1 0001 18:01*/class A {public synchronized void foo(B b) {System.out.println(当前线程名: Thread.currentThread().getName() 进入了A实例的foo方法); // ①try {Thread.sleep(200);} catch (InterruptedException ex) {ex.printStackTrace();}System.out.println(当前线程名: Thread.currentThread().getName() 企图调用B实例的last方法); // ③b.last();}public synchronized void last() {System.out.println(进入了A类的last方法内部);} } class B {public synchronized void bar(A a) {System.out.println(当前线程名: Thread.currentThread().getName() 进入了B实例的bar方法); // ②try {Thread.sleep(200);} catch (InterruptedException ex) {ex.printStackTrace();}System.out.println(当前线程名: Thread.currentThread().getName() 企图调用A实例的last方法); // ④a.last();}public synchronized void last() {System.out.println(进入了B类的last方法内部);} }public class DeadLock implements Runnable { //用实现Runnable接口的方式创建多线程A a new A();B b new B();public void init() {Thread.currentThread().setName(主线程);// 调用a对象的foo方法a.foo(b);System.out.println(进入了主线程之后);}public void run() {Thread.currentThread().setName(副线程);// 调用b对象的bar方法b.bar(a);System.out.println(进入了副线程之后);}public static void main(String[] args) {DeadLock dl new DeadLock();new Thread(dl).start(); //分线程创建并调用start()方法即调用run()方法dl.init(); //主线程调用init()方法} }分析 可以看到类A与类B里面定义了两个方法都加了synchronized就是同步方法同步监视器就是当前类的对象。 如下 然后在实现类里面声明了a与b两个成员变量还有两个方法如下 在main方法种创建了当前实现类DeadLock的对象dl然后将dl当作形参传入Thread()中用实现Runnable接口的方式创建一个线程调用start()方法于是这个分线程就去执行run()方法。 然后又使用dl调用init()方法这就是主线程的代码。就将dl当作普通的对象它调用init()方法。 现在就是主线程调用init()方法分线程调用run()方法。 分线程调用run方法主要执行b.bar(a); public void run() {Thread.currentThread().setName(副线程);// 调用b对象的bar方法b.bar(a);System.out.println(进入了副线程之后); }主线程调用init方法主要执行a.foo(b); public void init() {Thread.currentThread().setName(主线程);// 调用a对象的foo方法a.foo(b);System.out.println(进入了主线程之后); }可以得出主线程与分线程分别调用的方法如下 分线程调用bar方法需要拿着A类的一个对象a作为锁这个锁就是B的对象。 然后执行a.last()如下 注意锁是当前对象this用b调用bar(a)this就是b也就是拿着锁b进入了同步方法bar中顺便将参数a带进来了。 在执行最后有一个a.last()就是用对象a调用last()方法last方法也是一个同步方法a是传进来的A的对象相当于又需要握着a这个同步监视器。如下 也就是说分线程握着B的对象还要握A的对象。 主线程正好相反握着A的对象a又需要b的同步监视器。 输出结果 可以看见输出结果在这里出现了死锁僵持不动了。 3、案例3 public class TestDeadLock {public static void main(String[] args) {Object g new Object();Object m new Object();Owner s new Owner(g,m);Customer c new Customer(g,m);new Thread(s).start();new Thread(c).start();} } class Owner implements Runnable{private Object goods;private Object money;public Owner(Object goods, Object money) {super();this.goods goods;this.money money;}Overridepublic void run() {synchronized (goods) {System.out.println(先给钱);synchronized (money) {System.out.println(发货);}}} } class Customer implements Runnable{private Object goods;private Object money;public Customer(Object goods, Object money) {super();this.goods goods;this.money money;}Overridepublic void run() {synchronized (money) {System.out.println(先发货);synchronized (goods) {System.out.println(再给钱);}}} }3诱发死锁的原因及解决方案 1、诱发死锁的原因 ①互斥条件一定会出现 比如线程1握着同步监视器锁另外一个线程就无法获得这个锁。必然的这是同步机制加同步的目的就是为了某个线程能获得锁而另一个线程握不住 ②占用且等待 比如线程1握着同步监视器锁然后又等待另外一个锁。另外一个线程又拿着这个锁。 ③不可抢夺或不可抢占 某线程等待的时候不能将其他线程拥有的锁抢过来。 ④循环等待 这种情况会一直僵持着解不开。 以上4个条件同时出现就会触发死锁。 2、避免死锁 死锁一旦出现基本很难人为干预只能尽量规避。 可以考虑打破上面的任意一个诱发条件。 ①针对条件1互斥条件基本上无法被破坏。因为线程需要通过互斥解决安全问题。 ②针对条件2可以考虑一次性申请所有所需的资源这样就不存在等待的问题。 ③针对条件3占用部分资源的线程在进一步申请其他资源时如果申请不到就主动释放掉已经占用的资源让别人先来这样其他的线程不需要等待不会僵持了。 ④针对条件4可以将资源改为线性顺序。申请资源时先申请序号较小的这样避免循环等待问题按顺序获取先获取序号小的才能获取后边大的序号。 二、JDK5.0新特性Lock(锁) 1介绍 以前说的“同步机制”其实就是synchronized的使用方式。 除了使用synchronized同步机制处理线程安全问题之外还可以使用jdk5.0提供的Lock锁的方式。 除了synchronized的方式JDK5.0还提供了Lock锁的方式另外一种解决线程安全的方式。JDK5.0的新增功能保证线程的安全。与采用synchronized相比Lock可提供多种锁方案更灵活、更强大。Lock通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问每次只能有一个线程对Lock对象加锁线程开始访问共享资源之前应先获得Lock对象。在实现线程安全的控制中比较常用的是ReentrantLock可以显式加锁、释放锁。 ReentrantLock类实现了 Lock 接口它拥有与 synchronized 相同的并发性和内存语义但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外它还提供了在激烈争用情况下更佳的性能。 Lock锁也称同步锁加锁与释放锁方法如下 public void lock() 加同步锁。public void unlock() 释放同步锁。 代码结构 class A{//1. 创建Lock的实例必须确保多个线程共享同一个Lock实例private final ReentrantLock lock new ReenTrantLock();public void m(){//2. 调动lock()实现需共享的代码的锁定lock.lock();try{//保证线程安全的代码;}finally{//3. 调用unlock()释放共享代码的锁定lock.unlock(); }} }注意如果同步代码有异常要将unlock()写入finally语句块。 【举例】 import java.util.concurrent.locks.ReentrantLock;class Window implements Runnable{int ticket 100;//1. 创建Lock的实例必须确保多个线程共享同一个Lock实例private final ReentrantLock lock new ReentrantLock();public void run(){while(true){try{//2. 调动lock()实现需共享的代码的锁定lock.lock();if(ticket 0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(ticket--);}else{break;}}finally{//3. 调用unlock()释放共享代码的锁定lock.unlock();}}} }public class ThreadLock {public static void main(String[] args) {Window t new Window();Thread t1 new Thread(t);Thread t2 new Thread(t);t1.start();t2.start();} }2案例 【步骤】 步骤1创建Lock的实例需要确保多个线程共用同一个Lock实例。 需要考虑将此对象声明为static final。 步骤2.执行lock()方法锁定对共享资源的调用。 步骤3.unlock()的调用释放对共享数据的锁定。 以下面代码继承的方式为例 代码 package yuyi04.lock;/*** ClassName: WindowTest2* Package: yuyi04.lock* Description:* 使用继承Thread类的方式实现卖票* Author 雨翼轻尘* Create 2024/2/2 0002 9:54*/public class WindowTest2 {public static void main(String[] args) {//3.创建3个窗口 创建当前Thread的子类的对象Window w1new Window();Window w2new Window();Window w3new Window();//命名w1.setName(窗口1);w2.setName(窗口2);w3.setName(窗口3);//4.通过对象调用start(): 1.启动线程 2.调用当前线程的run()方法w1.start();w2.start();w3.start();}}class Window extends Thread{ //卖票 1.创建一个继承于Thread类的子类//票static int ticket100;//2.重写Thread类的run() —将此线程要执行的操作声明在此方法体中Overridepublic void run() {while (true){if(ticket0){ //如果票数大于0就可以售票try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//哪个窗口卖票了票卖了多少System.out.println(Thread.currentThread().getName() 售票票号为 ticket); //最开始票号为100ticket--;}else{break;}}} }输出 上面代码有线程安全问题。 现在我们用Lock来解决线程安全问题。 “concurrent”就是并发的意思Java的并发编程其实就是说这个包里面的API。 现在我们就可以看到这个包里面的一个API叫Lock它是一个接口目前已知的实现类如下 我们需要使用ReentrantLock可重入锁这个实现类接下来创建这个实现类的对象。 如下 class Window extends Thread{ //卖票 1.创建一个继承于Thread类的子类ReentrantLock locknew ReentrantLock();//... }①权限修饰 我们需要先考虑权限修饰。 首先不希望在外部可以被访问因为这纯粹是为了保证线程安全的所以加一个private。 其次这个锁有要求需要保证线程的安全多个线程需要共用同一个lock所以还要再加一个static。 最后再加一个final保证给lock赋值之后不要再修改了是唯一的不能改变的。 如下 private static final ReentrantLock locknew ReentrantLock();Runnable接口一般不需要static的一般是把这个接口的一个实例作为多个线程对象的形参一般情况只会有一个接口的实例。 ②用方法限制 这个锁定操作不像同步代码块有一个大括号里面是需要被同步的代码。 lock比较灵活它只需要用两个方法去限制两个方法执行当中的代码就是需要被同步的代码。 针对案例需要被同步的代码如下蓝色部分 在这一段代码之前调用一个方法lock()然后在代码执行结束调用unlock()方法。如下 两个方法中间的代码就是之前我们放到同步代码块当中的代码。 代码 package yuyi04.lock;import java.util.concurrent.locks.ReentrantLock;/*** ClassName: WindowTest2* Package: yuyi04.lock* Description:* 使用继承Thread类的方式实现卖票* Author 雨翼轻尘* Create 2024/2/2 0002 9:54*/public class WindowTest2 {public static void main(String[] args) {//3.创建3个窗口 创建当前Thread的子类的对象Window w1new Window();Window w2new Window();Window w3new Window();//命名w1.setName(窗口1);w2.setName(窗口2);w3.setName(窗口3);//4.通过对象调用start(): 1.启动线程 2.调用当前线程的run()方法w1.start();w2.start();w3.start();}}class Window extends Thread{ //卖票 1.创建一个继承于Thread类的子类//票static int ticket100;private static final ReentrantLock locknew ReentrantLock();//2.重写Thread类的run() —将此线程要执行的操作声明在此方法体中Overridepublic void run() {while (true){lock.lock();if(ticket0){ //如果票数大于0就可以售票try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//哪个窗口卖票了票卖了多少System.out.println(Thread.currentThread().getName() 售票票号为 ticket); //最开始票号为100ticket--;}else{break;}lock.unlock();}} }输出 可以看见线程安全了。 ️这里可能出现了没有解锁的场景 如果死锁的话就执行不到unlock虽然关闭了程序但是如果这些资源是指向别的资源的话就无法释放了。 unlock()方法一定要保证会被执行可以考虑写入finally中。 现在我们在这里加一个try将下面蓝色部分移入try里面 然后再写一个finally将unlock写入确保它一定会被执行。如下 代码 package yuyi04.lock;import java.util.concurrent.locks.ReentrantLock;/*** ClassName: WindowTest2* Package: yuyi04.lock* Description:* 使用继承Thread类的方式实现卖票* Author 雨翼轻尘* Create 2024/2/2 0002 9:54*/public class WindowTest2 {public static void main(String[] args) {//3.创建3个窗口 创建当前Thread的子类的对象Window w1new Window();Window w2new Window();Window w3new Window();//命名w1.setName(窗口1);w2.setName(窗口2);w3.setName(窗口3);//4.通过对象调用start(): 1.启动线程 2.调用当前线程的run()方法w1.start();w2.start();w3.start();}}class Window extends Thread{ //卖票 1.创建一个继承于Thread类的子类//票static int ticket100;//①创建Lock的实例(Lock是一个接口现在用的是可重入锁ReentrantLock)// 需要确保多个线程共用同一个Lcok实例需要考虑将此对象声明为static final//若没有加staticWindow一共造了3个对象相当于现在就有3把锁每一个对象锁自己的就不好使private static final ReentrantLock locknew ReentrantLock(); //2.重写Thread类的run() —将此线程要执行的操作声明在此方法体中Overridepublic void run() {while (true){try {//②执行lock()方法锁定对共享资源的调用lock.lock();if(ticket0){ //如果票数大于0就可以售票try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//哪个窗口卖票了票卖了多少System.out.println(Thread.currentThread().getName() 售票票号为 ticket); //最开始票号为100ticket--;}else{break;}}finally{//③unlock()的调用释放对共享数据的锁定解锁之后其他线程就可以来操作了lock.unlock();}}} }输出 可以看到程序结束了而且没有线程安全问题。如下 3synchronized与Lock的对比 synchronized与Lock的对比 1、Lock是显式锁手动开启和关闭锁别忘记关闭锁synchronized是隐式锁出了作用域、遇到异常等自动解锁。 2、Lock只有代码块锁synchronized有代码块锁和方法锁。 3、使用Lock锁JVM将花费较少的时间来调度线程性能更好。并且具有更好的扩展性提供更多的子类更体现面向对象。 4、了解Lock锁可以对读不加锁对写加锁synchronized不可以。 5、了解Lock锁可以有多种获取锁的方式可以从sleep的线程中抢到锁synchronized不可以。 说明 开发建议中处理线程安全问题优先使用顺序为 Lock ---- 同步代码块 ---- 同步方法 【面试题】 synchronized同步的方式 与Lock的对比 synchronized不管是同步代码块还是同步方法都需要在结束一对{}之后释放对同步监视器的调用。Lock是通过两个方法控制需要被同步的代码更灵活一些。Lock作为接口提供了多种实现类也就是很多锁适合更多更复杂的场景效率更高。 对于LockJUC里面再详细说这里不做深入。
http://www.zqtcl.cn/news/617985/

相关文章:

  • 企业网站建设的方案书网站镜像 cdn
  • 淘宝做网站的都是模板泉州模板建站公司
  • 清理网站数据库网站服务器租一个月
  • wordpress免费简约主题搜索引擎优化的英文
  • 瑞安门户网站建设怎么建设自己网站首页
  • 网站建设岗位周计划thinkphp微网站开发
  • 如何修改asp网站栏目帝国cms网站搬家教程
  • 网站建设与网页制作小团队兼职做网站
  • 嘉兴做网站的公司网红营销价值
  • scala做网站广州化妆品网站制作
  • 网站建设小组五类成员在线购物网站功能模块
  • 网站建设开发详细步骤流程图网站建设与管理实训报告总结
  • 网站设计的素材旅游网站建设标书
  • 做网站还得备案大企业网站建设多少钱
  • 一般做网站空间大概多少钱电商网站开发公司
  • 海报模板在线制作免费网站如何建设个人网站
  • 网站集群建设的意义如何优化推广网站
  • 怎么给公司做免费网站服装品牌网页设计图片
  • 中国通信建设协会网站新手建网站教程
  • 做网站页面的需要哪些技巧wordpress 网址导航
  • 如何做美食网站设计广州网页设计招聘
  • 中国商标网商标查询官方网站页面模板怎么添加文章
  • 建设基础化学网站的经验如何建设网站pdf下载
  • 外贸公司网站设计公司做网站能挣钱不
  • 免费网站ppt模板下载济南建设网站公司
  • 网站建设技术托管免费空间域名注册免备案
  • 威海住房建设部官方网站专科网站开发就业方向
  • 做外贸网站多少钱成都网页设计专业
  • 北京比较好的网站公司在线医生免费咨询
  • 免费的个人网站怎么做企业网站管理系统软件