多线程-4-线程同步、线程安全问题及死锁研究
来源:互联网 发布:nginx 域名访问 编辑:程序博客网 时间:2024/05/22 11:36
多线程编程优点是执行效率高,缺点就是太容易出现错误情况,这是因为多条线程访问同一资源,而线程代码有多条同时Java线程调度具有随机性造成的,当然如果在编程时能很好的注意这些问题,其实也是可以解决的。
0.知识体系
1.线程安全问题
下述代码就是有安全问题,安全问题出现的原因是因为CPU切换线程的不确定性造成的。
class BankAccount{private int money;public BankAccount(int money){this.money = money;}public void getMoney(int num){if(money > num){money -= num;System.out.println(Thread.currentThread().getName() + " 取钱 " + num +" 元;" + "余额 " + money);}else{System.out.println("余额不足");System.exit(0);}}}class Customer implements Runnable{private BankAccount account = null;public Customer(BankAccount account){this.account = account;}public void run(){while(true){account.getMoney(200);}}}public class ThreadSynTest {public static void main(String[] args) {BankAccount account = new BankAccount(1000);Customer ct1 = new Customer(account);Customer ct2 = new Customer(account);Thread t1 = new Thread(ct1);Thread t2 = new Thread(ct2);t1.start();t2.start();}}
2.解决方案
1)同步代码块
上述代码 不具有同步安全性,两个并发程序在修改账户时,正好发生切换。为解决这个问题,多线程引入了同步监视器解决,使用同步监视器的通用方法是同步代码块。语法如下:
synchronized(obj){//obj就是同步监视器 //code}
线程开始执行同步代码之前,必须先获得对同步监视器的锁定。任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码执行完成后,该线程释放对该同步监视器的锁定。阻止两个线程对同一个共享资源进行并发访问,因此通常推荐使用可能被并发访问的共享资源充当同步监视器。
利用同步代码块保持同步如下:
class BankAccount{private int money;public BankAccount(int money){this.money = money;}public void getMoney(int num){if(money > num){money -= num;System.out.println(Thread.currentThread().getName() + " 取钱 " + num +" 元;" + "余额 " + money);}else{System.out.println("余额不足");System.exit(0);}}}class Customer implements Runnable{private BankAccount account = null;public Customer(BankAccount account){this.account = account;}public void run(){while(true){try{Thread.sleep(100);}catch(InterruptedException ie){}synchronized(account){//进入同步代码块之前必须先获得对account账户的锁定account.getMoney(200);}}}}public class ThreadSynTest {public static void main(String[] args) {BankAccount account = new BankAccount(1000);Customer ct1 = new Customer(account);Customer ct2 = new Customer(account);Thread t1 = new Thread(ct1);Thread t2 = new Thread(ct2);t1.start();t2.start();}}
2)同步方法
通过使用同步方法方便实现线程安全的类,如下特征:
(1)该类的对象可以被多个线程安全地访问
(2)每个线程调用该对象的任意方法之后都将得到正确结果。
(3)每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。
synchronized关键字可以修饰方法,可以修饰代码块,但不能修饰构造器,属性等。
class BankAccount{private int money;public BankAccount(int money){this.money = money;}public synchronized void getMoney(int num){if(money > num){money -= num;System.out.println(Thread.currentThread().getName() + " 取钱 " + num +" 元;" + "余额 " + money);}else{System.out.println("余额不足");System.exit(0);}}}class Customer implements Runnable{private BankAccount account = null;public Customer(BankAccount account){this.account = account;}public void run(){while(true){try{Thread.sleep(100);}catch(InterruptedException ie){}synchronized(account){//进入同步代码块之前必须先获得对account账户的锁定account.getMoney(200);}}}}public class ThreadSynTest {public static void main(String[] args) {BankAccount account = new BankAccount(1000);Customer ct1 = new Customer(account);Customer ct2 = new Customer(account);Thread t1 = new Thread(ct1);Thread t2 = new Thread(ct2);t1.start();t2.start();}}
3)同步锁
Java5开始,Java提供了一种功能更强大的线程同步机制,通过显式定义同步锁对象来实现同步,在这种机制下,同步锁使用Lock对象充当。Lock提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock实现允许更灵活的结构,可以具有差别很大的属性,并且支持多个相关的Condition对象。
Lock是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
某些锁可能允许对共享资源并发访问,如ReadWriteLock(读写锁),Lock、ReadWriteLock是Java 5新提供的两个根接口,并为Lock提供了ReentrantLock(可重入锁)实现类;为ReadWriteLock提供了ReentrantReadWriteLock实现类。
在实现线程安全控制中,比较常用的是ReentrantLock(可重入锁),使用该Lock对象可以显式地加锁、释放锁,通常使用ReentrantLock代码如下:
class className{//定义锁对象private final ReentrantLock lock = new ReentrantLock();//定义需要保证线程安全的方法public void methodName(){//加锁lock.lock();try{//需要保证线程安全的代码}finally{lock.unlock();}}}
使用同步锁后的代码如下:
import java.util.concurrent.locks.ReentrantLock;class BankAccount{private ReentrantLock lock = new ReentrantLock();private int money;public BankAccount(int money){this.money = money;}public void getMoney(int num){lock.lock();try{if(money > num){money -= num;System.out.println(Thread.currentThread().getName() + " 取钱 " + num +" 元;" + "余额 " + money);}else{System.out.println("余额不足");System.exit(0);}}finally{lock.unlock();}}}class Customer implements Runnable{private BankAccount account = null;public Customer(BankAccount account){this.account = account;}public void run(){while(true){try{Thread.sleep(100);}catch(InterruptedException ie){}synchronized(account){//进入同步代码块之前必须先获得对account账户的锁定account.getMoney(200);}}}}public class ThreadSynTest {public static void main(String[] args) {BankAccount account = new BankAccount(1000);Customer ct1 = new Customer(account);Customer ct2 = new Customer(account);Thread t1 = new Thread(ct1);Thread t2 = new Thread(ct2);t1.start();t2.start();}}
3.死锁研究
1)产生死锁的原因
下面是一个死锁例子:
class Locks{public static final Object lockA = new Object();public static final Object lockB = new Object();}class PublicTarget{public static void showInfo(){System.out.println("----" + Thread.currentThread().getName() + " 拿到两锁----");}}class Accesser implements Runnable {private boolean flag = true;public void run(){if(flag){synchronized(Locks.lockA){flag = false;System.out.println(Thread.currentThread().getName() + " 拿到lockA锁");try{Thread.sleep(100);}catch(InterruptedException ex){}synchronized(Locks.lockB){System.out.println(Thread.currentThread().getName() + " 拿到lockB锁");PublicTarget.showInfo();}}}else{synchronized(Locks.lockB){flag = true;System.out.println(Thread.currentThread().getName() + " 拿到lockB锁");try{Thread.sleep(100);}catch(InterruptedException ex){}synchronized(Locks.lockA){System.out.println(Thread.currentThread().getName() + " 拿到lockA锁");PublicTarget.showInfo();}}}}}public class DeadLockTest{public static void main(String[] args){Accesser accesser = new Accesser();Thread a = new Thread(accesser);Thread b = new Thread(accesser);a.start();b.start();}}
2)死锁的预防
待补充...
0 0
- 多线程-4-线程同步、线程安全问题及死锁研究
- Android多线程研究(3)——线程同步和互斥及死锁
- 线程详解、多线程及安全问题
- 线程同步---线程安全问题
- 多线程模拟售票及线程同步与死锁
- Java笔记3 多线程<1>线程概述、多线程的创建、多线程的安全问题、静态同步函数的锁、死锁
- java线程研究---(10)Thread同步:死锁
- 线程同步 线程死锁
- 线程同步/线程死锁
- Java线程安全问题——同步和死锁
- 多线程(四)线程的同步之线程安全问题
- 多线程--线程同步、死锁、守护线程、多线程下载
- Java多线程之线程同步和死锁
- Java多线程 线程同步与死锁
- 关于同步线程安全问题
- 线程同步——死锁及举例
- 线程的同步与死锁及解决办法
- 多线程:线程的安全问题
- 第七周作业3 最长递增子序列
- Latex 制作标准论文参考文献工作任务
- Activity与Service是否处于同一进程?
- 亚洲最大高考工厂打造书呆子流水线?
- 黑马程序员-生产者消费者模式
- 多线程-4-线程同步、线程安全问题及死锁研究
- Android Intent 传值 --onActivityResult
- 第四周作业-----图的表示
- Mysql存储过程中使用cursor
- 奇葩男的相亲史,笑翻了
- [LeetCode] Minimum Path Sum
- “撕书狂欢”能否折射中国式教育之病态?
- 黑马程序员_java基础三(IO和GUI)
- Hadoop 专题理论学习与技术实践