多线程-线程安全问题
2020-08-18 17:58
483 查看
线程安全问题
什么是线程安全问题?
答:看下面这个例子,有时候执行出来余票会出现-1或-2,虽然我们已经在循环的时候限制了余票(count>0),但是依然会出现这个问题,这就是线程安全问题。
//因线程不安全,出现问题的案例 public class Demo7 { public static void main(String[] args) { //线程不安全 Runnable run = new Ticket(); new Thread(run).start(); new Thread(run).start(); new Thread(run).start(); } static class Ticket implements Runnable{ //总票数 private int count = 10; @Override public void run() { while (count>0){ //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println("卖票结束,余票:"+count); } } } }
这个问题是如何产生的?
分析:三个进程都进入到while循环,但count数量已经不能满足三个线程去减依然大于0,然后就会出现count等于-1或-2的情况,显然这不是我们想要的结果。
那么如何去解决这个问题呢?
答:要解决问题首先要分析产生的原因,上面我们已经分析过了产生原因,这段代码是因为while(count > 0)这个判断与count - -之间的间隔部分被其他进程闯入导致的,那我们只要不让while(count > 0)与count - -中间执行的间隔进入别的进程就行了。
思路很简单那么怎么实现,这个可以实现吗?
答:下面就来看下怎么实现这个想法
解决方案1-同步代码块
synchronized (锁对象) {锁上的代码块}
//线程同步synchronized public class Demo8 { public static void main(String[] args) { Object o = new Object(); //线程不安全 //解决方案1 同步代码块 //格式:synchronized(锁对象){ // // // } Runnable run = new Ticket(); new Thread(run).start(); new Thread(run).start(); new Thread(run).start(); } static class Ticket implements Runnable{ //总票数 private int count = 10; private Object o = new Object(); @Override public void run() { //Object o = new Object(); //这里不是同一把锁,所以锁不住 while (true) { synchronized (o) { if (count > 0) { //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count); }else { break; } } } } } }
注意:需要用同一把锁才可以锁上
解决方案2-同步方法
方法权限修饰符后加synchronized
//线程同步synchronized public class Demo9 { public static void main(String[] args) { Object o = new Object(); //线程不安全 //解决方案2 同步方法 Runnable run = new Ticket(); new Thread(run).start(); new Thread(run).start(); new Thread(run).start(); } static class Ticket implements Runnable{ //总票数 private int count = 10; @Override public void run() { while (true) { boolean flag = sale(); if(!flag){ break; } } } public synchronized boolean sale(){ if (count > 0) { //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count); return true; } return false; } } }
- 如果是是静态方法锁对象是类名.class
- 如果不是静态方法锁对象是this
- 不同对象对应的锁不同
//锁不同 new Thread(new Thread()).start(); new Thread(new Ticket()).start(); new Thread(new Thread()).start(); //锁相同 Runnable run = new Ticket(); new Thread(run).start(); new Thread(run).start(); new Thread(run).start();
- 如果同步代码块锁对象是this,则下面的同步方法也被上锁。
//可以锁住后面的同步方法 synchronized (this){ }
解决方案3-显示锁Lock
- 同步代码块和同步方法都属于隐式锁
创建锁对象
Lock l = new ReentrantLock(false);
上锁
l.lock();
解锁
l.unlock();
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //同步代码块和同步方法都属于隐式锁 //线程同步lock public class Demo10 { public static void main(String[] args) { Object o = new Object(); //线程不安全 //解决方案3 显示锁 Lock 子类 ReentrantLock Runnable run = new Ticket(); new Thread(run).start(); new Thread(run).start(); new Thread(run).start(); } static class Ticket implements Runnable{ //总票数 private int count = 10; //参数为true表示公平锁 默认是false 不是公平锁 private Lock l = new ReentrantLock(); @Override public void run() { while (true) { l.lock();if (count > 0) { //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count); }else { break; } l.unlock(); } } } }
- 非公平锁:(抢占)上面三种都是非公平锁
- 公平锁:(排队)
//参数为true表示公平锁 默认是false 不是公平锁 Lock l = new ReentrantLock(true);
相关文章推荐
- 在多线程中使用静态方法是否有线程安全问题
- 多线程-线程安全问题的产生原因分析以及同步代码块的方式解决线程安全问题
- 【我的Java笔记】多线程_使用Lock锁对象解决线程安全问题
- 12-多线程(卖票示例)1 2 14-多线程(线程安全问题产生的原因)
- 多线程-生产者消费者问题代码2并解决线程安全问题
- java进程、线程、多线程以及线程安全问题
- C#多线程和线程安全问题
- 多线程线程安全问题
- 在多线程中使用静态方法是否有线程安全问题
- 在多线程中使用静态方法是否有线程安全问题
- 多线程_生产者消费者题代码2并解决线程安全问题
- 在多线程中使用静态方法是否有线程安全问题
- 在多线程中使用静态方法时候会有线程安全问题
- java多线程学习7-线程安全问题
- 在多线程中使用静态方法是否有线程安全问题
- 多线程-同步代码块解决线程安全问题的解释以及同步的特点及好处和弊端
- 8. Java入门之线程是什么?多线程的开启与使用、同步技术解决线程安全问题、等待唤醒机制的应用
- Java 多线程 线程安全问题
- java语言基础(91)——多线程(同步方法解决线程安全问题)
- 多线程编程-线程安全问题浅谈(附懒汉式单例)