Java学习笔记45(多线程二:安全问题以及解决原理)
2018-01-20 12:49
701 查看
线程安全问题以及解决原理:
多个线程用一个共享数据时候出现安全问题
一个经典案例:
电影院卖票,共有100座位,最多卖100张票,买票方式有多种,网上购买、自主售票机、排队购买
三种方式操作同一个共享数据,这时候会出现安全问题:
示例:
一般不会出现问题,但是要想到这种问题
但是,假设只剩下最后最后一张票,一个线程抢到CPU资源执行,在判断结束时候,CPU资源被其他线程抢到,其他线程判断然后执行,
这时候轮到开始时候的线程,由于已经判断完,继续执行,这时候票数就会变成负数,这里就出现了问题
解决方法:
同步代码块
原理:一个线程进入数据操作的时候,阻止其他线程执行
不过,虽然安全了,但是运行速度下降
但是,我们为了安全性可以不顾及速度,无论如何都要保证安全性
这里传入的对象参数简称作:同步锁,专业名称:对象监视器
原理:
没有锁的线程不能执行,只能等待
线程遇到同步代码块后判断是否有同步锁,如果有,拿走锁,进入同步中执行,执行完毕后将锁对象还回去
另一个线程遇到代码块后没有锁,无法进入,原来的线程把锁还回去之后新线程再获取锁,循环下去
这里明显可以看出,这么多的过程,速度自然就慢下来了
采用同步方法解决问题:
优点:代码量更低
缺点:如果出现了异常,方法的锁对象没有释放,不出同步,锁不会释放
这里就需要用到一个Lock接口:
提供了更广泛的锁定操作
改进之前的售票案例:
死锁:
同步锁引发的弊端:
当线程任务中出现了多个同步时,如果同步中嵌套了其他的同步,这时候就会引发一种现象,程序出现无限等待,这种现象称之为死锁
通俗解释:两个人吃一碗面,却只有一双筷子,两个人一人抢到一支筷子,规定不能用手抓,这时候就无法吃面
代码实现:
运行后发现,会卡在某一处不动,但是并没有停止
多个线程用一个共享数据时候出现安全问题
一个经典案例:
电影院卖票,共有100座位,最多卖100张票,买票方式有多种,网上购买、自主售票机、排队购买
三种方式操作同一个共享数据,这时候会出现安全问题:
示例:
package demo1; public class Tickets implements Runnable { private int ticket = 100; public void run(){ while(true){ if (ticket>0) { System.out.println(Thread.currentThread().getName()+"出售第"+ticket--+"张票"); } } } }
package demo1; public class ThreadDemo { public static void main(String[] args) { Tickets t = new Tickets(); Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); } }
一般不会出现问题,但是要想到这种问题
但是,假设只剩下最后最后一张票,一个线程抢到CPU资源执行,在判断结束时候,CPU资源被其他线程抢到,其他线程判断然后执行,
这时候轮到开始时候的线程,由于已经判断完,继续执行,这时候票数就会变成负数,这里就出现了问题
解决方法:
同步代码块
原理:一个线程进入数据操作的时候,阻止其他线程执行
package demo1; public class Tickets implements Runnable { private int ticket = 100; private Object obj1 = new Object(); public void run() { while (true) { synchronized (obj1) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "张票"); } } } } }
不过,虽然安全了,但是运行速度下降
但是,我们为了安全性可以不顾及速度,无论如何都要保证安全性
这里传入的对象参数简称作:同步锁,专业名称:对象监视器
原理:
没有锁的线程不能执行,只能等待
线程遇到同步代码块后判断是否有同步锁,如果有,拿走锁,进入同步中执行,执行完毕后将锁对象还回去
另一个线程遇到代码块后没有锁,无法进入,原来的线程把锁还回去之后新线程再获取锁,循环下去
这里明显可以看出,这么多的过程,速度自然就慢下来了
采用同步方法解决问题:
优点:代码量更低
package demo1; public class Tickets implements Runnable { private int ticket = 100; public void run() { while (true) { payTicket(); } } public synchronized void payTicket() { //同步方法的对象锁是本类对象引用:即为this //静态方法的锁是本类类名.class if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "张票"); } } }
缺点:如果出现了异常,方法的锁对象没有释放,不出同步,锁不会释放
这里就需要用到一个Lock接口:
提供了更广泛的锁定操作
改进之前的售票案例:
package demo1; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Tickets implements Runnable { private int ticket = 100; private Lock lock = new ReentrantLock(); public void run() { while (true) { lock.lock(); if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "张票"); } lock.unlock(); } } }
死锁:
同步锁引发的弊端:
当线程任务中出现了多个同步时,如果同步中嵌套了其他的同步,这时候就会引发一种现象,程序出现无限等待,这种现象称之为死锁
通俗解释:两个人吃一碗面,却只有一双筷子,两个人一人抢到一支筷子,规定不能用手抓,这时候就无法吃面
代码实现:
package demo1; public class LockA { private LockA(){} public final static LockA locka =new LockA(); }
package demo1; public class LockB { private LockB(){} public final static LockB lockb =new LockB(); }
package demo1; public class DeadLock implements Runnable { private int i = 0; public void run() { while (true) { if (i % 2 == 0) { synchronized (LockA.locka) { System.out.println("if...locka"); synchronized (LockB.lockb) { System.out.println("if...lockb"); } } } else { synchronized (LockB.lockb) { System.out.println("else...lockb"); synchronized (LockA.locka) { System.out.println("else...locka"); } } } i++; } } }
package demo1; public class DeadLockDemo { public static void main(String[] args) { DeadLock dead = new DeadLock(); Thread t0 = new Thread(dead); Thread t1 = new Thread(dead); t0.start(); t1.start(); } }
运行后发现,会卡在某一处不动,但是并没有停止
相关文章推荐
- Java 学习笔记16:用ThreadLocal解决多线程安全问题
- Java学习笔记47(JDBC、SQL注入攻击原理以及解决)
- java学习笔记---第一个applet程序以及一个小问题的解决
- java 多线程学习之多生产者多消费者产生的线程安全问题分析与解决:Lock和Condition
- java中多线程的安全问题以及解决办法
- (47)Java学习笔记——多线程 / 线程的安全问题
- 4000 java中多线程的安全问题以及解决办法(2)
- 黑马程序员_多线程之同步问题的前期,以及安全问题的发现和解决
- Java笔记3 多线程<1>线程概述、多线程的创建、多线程的安全问题、静态同步函数的锁、死锁
- Java学习笔记37:Spring 使用 @ResponseBody 返回中文乱码问题解决
- [学习笔记]Java多线程经典问题
- 黑马程序员自学笔记————字符编码原理,以及开发中常见的问题的解决方法:
- java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)
- [零散篇]Java学习笔记---Java的Socket网络编程以及多线程
- java 学习-----多线程的安全问题
- JAVA学习笔记之多线程专题(一):线程同步安全处理
- Java学习笔记--解决一个类实现多个接口的问题
- 黑马程序员——java中关于同步函数(或同步代码块)解决多线程安全问题的加锁
- 黑马程序员_学习笔记4 IO流以及正则表达式解决一个传智播客的问题
- java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提