如何解决多线程并发访问一个资源的安全性问题?

您所在的位置:网站首页 多线程操作同一对象 如何解决多线程并发访问一个资源的安全性问题?

如何解决多线程并发访问一个资源的安全性问题?

2024-07-10 07:57| 来源: 网络整理| 查看: 265

原子操作:所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切[1] 换到另一个线程)。 关于我对原子操作的理解:原子操作就类似于化学中的原子为不可分割的单位,也就是如果把需要操作的代码块能够顺序执行中间不为被干扰。 这样就不会出现线程不安全情况(案例中的购票系统出现负数的情况),这种原子操作思想还是挺有用的,在这提提自己也不了解=-=。 解决方案:保证打印编号和操作必须同步执行:System.out.println(Thread.currentThread().getName()+”—卖出的票”+tickets–); 也就是上述代码中ticket–与输出同步执行,不能因为某个线程输出后就休眠而不执行减减操作。

方式一、同步代码块: 语法:

synchronize(同步锁){ 需要同步操作的代码 }

案例:

package com.test; //线程安全 public class Main { public static void main(String[] args){ SaleThread saleThread=new SaleThread(); new Thread(saleThread,"线程一").start(); new Thread(saleThread,"线程二").start(); new Thread(saleThread,"线程三").start(); new Thread(saleThread,"线程四").start(); } } class SaleThread implements Runnable{ private int tickets=10; public void run(){ //synchronized (this) { while(tickets>0){ try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--); // } } } }

*输出结果: 线程二—卖出的票10 线程一—卖出的票9 线程四—卖出的票8 线程三—卖出的票7 线程二—卖出的票5 线程一—卖出的票6 线程三—卖出的票4 线程四—卖出的票3 线程一—卖出的票1 线程二—卖出的票2 线程三—卖出的票-1 线程四—卖出的票0* 分析:上述结果中出现负数和0情况(如果数据量大还会出现重复情况)。

方式二、同步方法 使用synchronized修饰的方法就叫同步方法,表示a线程在执行该方法的时候其他线程只能等待。 代码:

synchronized public void run(){ while(tickets>0){ try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--); } **问题来了上述代码中synchronized中的同步锁是谁?** 对于非static方法同步锁就是this 对于static方法,我们使用当前方法所在类的字节码对象(当前类名.class)

方式三、同步锁-锁机制lock 为了保证每个线程都能正常执行原子操作,java引入了线程同步机制。 同步监听对象/同步锁/同步监听器/互斥锁(a进去b被排斥,保证只有一个进程执行) 对象的同步锁只是一个概念,可以想象为在对象上标记一个锁。 java程序运行使用任何对象作为同步监听对象,但是一般的,我们试验当前并发访问的共同资源作为同步监听对象。 注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他线程只能等待。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3