运用了高内聚低耦合的方法
- 创建资源类,在资源类创建属性和方法
- 创建多个线程,调用资源类的 *** 作方法
synchronized锁上锁和解锁的过程由jvm隐式的完成
Lock接口可以手动的实现上锁和解锁的过程
ReentrantLock(可重入锁)ReentrantLock是lock接口的一个实现类,使用可重入锁的方法对线程的同步来进行控制
可重入锁:进入上锁退出解锁 主要的区别在于需要手动的上锁和解锁。
package com.xiaoxu.lock; import java.util.concurrent.locks.ReentrantLock; //创建资源类 class LTicket{ //创建可重入锁 private final ReentrantLock lock = new ReentrantLock(); private int number=30; //卖票的方法 public void sale(){ //上锁 lock.lock(); try { //判读是否有票可卖 if(number>0){ System.out.println(Thread.currentThread().getName()+"卖出了第"+(+number--)+"张票"); } }finally { //解锁 lock.unlock(); } } } public class LSaleTicket { public static void main(String[] args) { LTicket ticket = new LTicket(); //lamber表达式 new Thread(()->{ for (int i = 0; i < 40; i++) { ticket.sale(); } },"AA").start(); new Thread(()->{ for (int i = 0; i < 40; i++) { ticket.sale(); } },"BB").start(); new Thread(()->{ for (int i = 0; i < 40; i++) { ticket.sale(); } },"CC").start(); } }
通过可重入锁多线程买票的并发问题,对卖票的过程加锁来解决了线程之间的不安全问题。
其中Lock是一个接口,在发生异常的时候不会和synchronized一样自动的释放锁,可能会引起死锁现象。
线程之间的通信多线程编程的步骤2
-
创建资源类
-
在资源类中 *** 作方法 判读 干活 通知。
-
创建多个线程,调用资源类 *** 作方法,完成过程。
-
防止虚假唤醒的问题
实例一:a(add)线程 +1 b线程 -1
变量值为1的时候加1 0的时候a线程等待。
实现方式synchronized关键字实现和lock锁的实现方式
synchronized实现方式package com.xiaoxu.synchroniz; //创建资源类 class Share{ //初始值 private int number = 0; //+1的方法 public synchronized void incr() throws InterruptedException { if (number!=0){ //判断number是否为0 等待 this.wait(); } //如果number的值是0就加1 *** 作 number++; System.out.println(Thread.currentThread().getName()+"::"+number); //通知其他的线程(个人理解就是解锁) this.notifyAll(); } public synchronized void decr() throws InterruptedException { if(number!=1){ this.wait(); } //实现步骤 number--; System.out.println(Thread.currentThread().getName()+"::"+number); //通知其他的线程 this.notifyAll(); } } public class ThreadDemo1 { public static void main(String[] args) { Share share = new Share(); //创建多个线程 new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tjw4cGRq-1638446376730)(C:UsersLenovoAppDataRoamingTyporatypora-user-imagesimage-20211202155350256.png)]
线程之间的通信虚假唤醒问题产生虚假唤醒问题的代码
package com.xiaoxu.synchroniz; //创建资源类 class Share{ //初始值 private int number = 0; //+1的方法 public synchronized void incr() throws InterruptedException { if (number!=0){ //判断number是否为0 等待 this.wait(); } //如果number的值是0就加1 *** 作 number++; System.out.println(Thread.currentThread().getName()+"::"+number); //通知其他的线程(个人理解就是解锁) this.notifyAll(); } public synchronized void decr() throws InterruptedException { if(number!=1){ this.wait(); } //实现步骤 number--; System.out.println(Thread.currentThread().getName()+"::"+number); //通知其他的线程 this.notifyAll(); } } public class ThreadDemo1 { public static void main(String[] args) { Share share = new Share(); //创建多个线程 new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStakTrace(); } } },"DD").start(); } }
产生虚假唤醒的原因:线程的虚假唤醒的问题。wait()方法释放锁之后,如果该线程继续抢到cpu的资源之后,会在wait()语句这里唤醒,if语句的判断会失效。解决的方法是将if语句换成对应的while语句解决虚假唤醒的问题。
下面是将原来的资源类中对资源进行 *** 作的方法中进行锁条件判断语句中的if替换为while之后解决的过程。
package com.xiaoxu.synchroniz; //创建资源类 class Share{ //初始值 private int number = 0; //+1的方法 public synchronized void incr() throws InterruptedException { while (number!=0){ //判断number是否为0 等待 this.wait(); } //如果number的值是0就加1 *** 作 number++; System.out.println(Thread.currentThread().getName()+"::"+number); //通知其他的线程(个人理解就是解锁) this.notifyAll(); } public synchronized void decr() throws InterruptedException { while (number!=1){ this.wait(); } //实现步骤 number--; System.out.println(Thread.currentThread().getName()+"::"+number); //通知其他的线程 this.notifyAll(); } } public class ThreadDemo1 { public static void main(String[] args) { Share share = new Share(); //创建多个线程 new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"DD").start(); } }Lock接口实现
package com.xiaoxu.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //创建资源类 class Share{ private int number = 0; //创建lock private Lock lock= new ReentrantLock(); private Condition condition=lock.newCondition(); //+1 public void incr() throws InterruptedException { //加锁 lock.lock(); try { //判断 while (number!=0){ condition.await(); } // *** 作 number++; System.out.println(Thread.currentThread().getName()+"::"+number); //唤醒 condition.notify(); }finally { //解锁 lock.unlock(); } } //-1 public void decr() throws InterruptedException { //上锁 lock.lock(); try { while (number!=1){ condition.await(); } number--; System.out.println(Thread.currentThread().getName()+"::"+number); condition.notify(); }finally { //解锁 lock.unlock(); } } } public class ThreadDemo2 { public static void main(String[] args) { Share share = new Share(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); } }线程的定制化通信
应用场景:
启动三个线程按照如下的要求进行
AA打印5次 BB打印10次 CC打印15次共执行10轮
使我们线程之间的顺序按照指定的顺序进行。思路为三个线程设置三个标志位。标志位1打印A5次 修改标志位为2通知B过程以此类推。最后一个CC线程的标志位改完1。完成 *** 作。下面对代码进行实现。
package com.xiaoxu.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //第一步 创建资源类 class ShareResource{ //定义标志位 private int flag = 1; //1 AA 2BB 3CC //创建lock锁 private Lock lock = new ReentrantLock(); //创建三个condition private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); //打印5次 public void print5(int loop) throws InterruptedException { lock.lock(); try{ //判断 while (flag!=1){ c1.await(); } //干活 for (int i = 1; i <=5; i++) { System.out.println(Thread.currentThread().getName()+"::"+i+"轮数"+loop); } //通知 flag = 2; c2.signal(); }finally { //释放锁 lock.unlock(); } } public void print10(int loop) throws InterruptedException { //上锁操作 lock.lock(); try { while (flag!=2){ c2.await(); } for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName()+"::"+i+"轮数"+loop); } //修改标志位 进行通知Cc线程 flag = 3; c3.signal(); }finally { //解锁 lock.unlock(); } } public void print15(int loop) throws InterruptedException { //上锁操作 lock.lock(); try { while (flag!=3){ c3.await(); } for (int i = 1; i <= 15; i++) { System.out.println(Thread.currentThread().getName()+"::"+i+"轮数"+loop); } //修改标志位 进行通知Cc线程 flag = 1; c1.signal(); }finally { //解锁 lock.unlock(); } } } public class ThreadDemo3 { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); //创建多线程 new Thread(()->{ for (int i = 1; i <= 10; i++) { try { shareResource.print5(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 1; i <= 10; i++) { try { shareResource.print10(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(()->{ for (int i = 1; i <= 10; i++) { try { shareResource.print15(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)