您的位置 首页 java

Java学习:线程的安全问题

线程的安全问题

模拟卖票案例

创建三个的线程,同时开启,对共享的票进行出售

public class RunnableImpl implementsc Runnable{
 //定义一个 多线程 共享的票源
 private int ticket = 100;
 
 //设置线程任务:买票
 @Override
 public void run(){
 //使用死循环,让卖票操作重复执行
 while (true){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try{
  Thread .sleep(10);
 }catch (InterruptedException e){
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
 ticket --;
 }
 }
 }
}
public class CaiNiao{
 public static void main(String[] args){
 //创建Runnable接口的实现类对象
 RunnableImpl run = new RunnableImpl();
 //创建Thread类对象,构造方法中传递Runnable接口的实现类对象
 Thread t0 = new Thread(run); 
 Thread t1 = new Thread(run); 
 Thread t2 = new Thread(run); 
 //调用start方法开启多线程
 t0.start();
 t1.start();
 t2.start();
 }
}
 

这样会导致一个结果

  • Thread-0 –>正在卖第1张票
  • Thread-1 –>正在卖第1张票
  • Thread-2 –>正在卖第0张票

解决线程安全问题的一种方案 :使用同步代码块

格式:

格式:
 syncharonized(锁对象){
 可能会出现线程安全问题的代码(访问了共享数据的代码) 
 }
 

注意:

  • 通过代码块中的锁对象,可以使用任意的对象
  • 但是必须要保证多个线程使用的锁对象是同一个

锁对象作用

  • 把同步代码块锁住,只让一个线程在同步代码中执行
public class RunnableImpl implementsc Runnable{
 //定义一个多线程共享的票源
 private int ticket = 100;
 
 //设置线程任务:买票
 @Override
 public void run(){
 //使用死循环,让卖票操作重复执行
 while (true){
 //同步代码块
 syncharonized(obj){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try{
 Thread.sleep(10);
 }catch (InterruptedException e){
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
 ticket --; 
 }
 

解决线程安全问题的二种方案:使用同步方法

使用步骤:

  1. 把访问了共享数据的代码抽取出来,放到一个方法中
  2. 在方法上添加 synchronized 修饰符

格式: 定义方法的格式

 修饰符 synchronized 返回值类型 方法名(参数列表){
 可能会出现线程安全问题的代码(访问了共享数据的代码)
 }
 

解决线程安全问题的三种方案:使用 Lock

java .util.concurrent.Locks.Lock接口

Lock实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作。

Lock接口中的方法:

  void Lock()获取锁
  void unLock() 释放锁
java.util.concurrent.Locks.ReentrantLock implements Lock 接口
 

使用步骤:

  1. 在成员位置创建一个ReentrantLock对象
  2. 在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取锁
  3. 在可能会出现安全问题的代码前调后用Lock接口中的方法unLock释放锁

/

//1.在成员位置创建一个ReentrantLock对象
Lock l = new ReentrantLock();
@Override
 public void run(){
 //使用死循环,让卖票操作重复执行
 while (true){
 //2. 在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取锁
 l.lock();
 
 //同步代码块
 syncharonized(obj){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try{
 Thread.sleep(10);
 }catch (InterruptedException e){
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
 ticket --; 
 }
 //3.在可能会出现安全问题的代码前调后用Lock接口中的方法unLock释放锁
 l.unLock();//无论程序释放异常,锁都会释放
 
 

文章来源:智云一二三科技

文章标题:Java学习:线程的安全问题

文章地址:https://www.zhihuclub.com/181150.shtml

关于作者: 智云科技

热门文章

网站地图