千家信息网

Java线程安全与同步实例分析

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,本篇内容介绍了"Java线程安全与同步实例分析"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!线程安全
千家信息网最后更新 2025年01月19日Java线程安全与同步实例分析

本篇内容介绍了"Java线程安全与同步实例分析"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

线程安全问题

多个线程可能会共享(访问)同一个资源

比如访问同一个对象,同一个变量,同一个文件

当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题,称为线程安全问题

什么情况下会出现线程安全问题

多个线程共享同一个资源

且至少有一个线程正在执行写的操作

实例:

存钱取钱问题

分别有存钱和取钱2个线程

存钱 取钱
线程1 余额 线程2
1000 《----1000------》 1000
1000+1000-----》2000
500 《-----1000-500

正确:结束后余额应该是1500,而不是500

买票问题

有卖票2个线程

卖票 卖票
线程1 票数 线程2
1000 《----1000------》 1000
1000-1-----》999
999 《-----1000-1

正确:结束后余额应该是998,而不是999

买票问题错误(未线程同步)实例:

public class love implements Runnable{    private int piao=3000;//有3000张票    public boolean sale() {//ture代表还有票;false代表没有票了        if(piao<1) return false;         piao--;//卖1张票                  //细化piao--;         //寄存器=piao;         //寄存器=寄存器-1;         //piao=寄存器;                  String sk =Thread.currentThread().getName();//获取当前线程(买票窗口)的名字         System.out.println(sk+"卖了1张票,还剩下"+piao+"张");         return piao>1;    }    public void run() {         while(sale());//循环执行;直至卖完票返回false    }} public class Main {    public static void main(String[] a) {        love tjlove =new love();        for(int i=1;i<=4;i++) {//循环4次;产生4个线程(窗口)卖票            Thread tj = new Thread(tjlove());            tj.setName(""+i);            tj.start();        }    }}

部分输出结果:

线程安全问题

分析问题

线程A和B对类中1个变量值为17进行+1操作
最终结果为2个18

解决方案

加锁:

过程:首先线程A先访问到这个17,读上来后进行加锁并进去+1的操作改为18
并且17在加锁期间其它线程都不能访问
改完之后再进行写入,然后再解锁17
然后再由线程B去访问它,再进行加锁,重复上面操作变成19再解锁
这样做能保证在同一时间只有1个线程去访问它,这样就保证了安全;之前错误是由于这些线程一起去访问了它

线程同步

刚刚所说的加锁操作便是线程同步技术

可以使用线程同步技术来解决线程安全问题

线程同步在Java里有2种做法:

1.同步语句

2.同步方法

同步语句

public class love implements Runnable{        private int piao=3000;//本人cpu单核性能过强,数据量大些才能看到是4个线程在卖票        public boolean sale() {                synchronized(this) {//1个线程获取这个对象的锁,并加锁;    synchronized作用于整个语句                //this指向当前对象                //不能用new Object();这样会产生新的对象,产生新的锁                //把this换成"123",效果基本一样;因为其存在常量值里,每次访问的对象一样                        if(piao<1) return false;                        piao--;                        String sk =Thread.currentThread().getName();                        System.out.println(sk+"卖了1张票,还剩下"+piao+"张");                        return piao>0;                        }        }        public void run() {                 while(sale());        }}

部分输出结果:

synchronize(obj)的原理

1.每个对象都有一个与它相关的内部锁(intrinsic lock)或者叫监视器锁(monitor lock)

2.第一个执行到同步语句的线程可以获得 obj 的内部锁,在执行完同步语句中的代码后释放此锁

3.只要一个线程持有了内部锁,那么其它线程在同一时刻将无法再获得此锁

✓ 当它们试图获取此锁时,将会进入BLOCKED状态

4.多个线程访问同一个 synchronized(obj)语句时

obj必须是同一个对象,才能起到同步的作用

同步方法

public class love implements Runnable{    private int piao=3000;    public synchronized boolean sale() { //synchronized作用于整个方法            if(piao<1) return false;            piao--;            String sk =Thread.currentThread().getName();            System.out.println(sk+"卖了1张票,还剩下"+piao+"张");            return piao>0;    }    public void run() {         while(sale());    }}

synchronized不能修饰构造方法

同步方法的本质

实例方法:synchronized (this)

静态方法:synchronized (Class对象)

同步语句比同步方法更灵活一点

同步语句可以精确控制需要加锁的代码范围,减少处于BLOCKED状态的线程,充分利用劳动力

使用了线程同步技术后

虽然解决了线程安全问题,但是降低了程序的执行效率

因为加了锁就会有处于等待的线程,多了加锁解锁的操作

所以在真正有必要的时候,才使用线程同步技术

"Java线程安全与同步实例分析"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

线程 同步 问题 安全 对象 方法 语句 实例 卖票 多个 技术 分析 余额 作用 取钱 数据 结果 资源 输出 实例分析 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 web数据库设计讲解 戴尔服务器拔掉硬盘报警 学软件开发的五年大专学费 Java怎样调用数据库中的函数 锦江区猫头鹰软件开发工作室 群晖 其他硬盘的数据库 天津服务器迁移选哪家云服务器 服务器cpu型号大小 ftp 服务器上传 服务器维护和管理的重要性 无服务器架构需要长期维护吗 excel如何连接阿里云数据库 电厂网络安全管理办法 国动网络技术有限公司联系方式 网络安全红蓝对抗人员配置 金融网络技术风险 数据库如何区分几个范式 站群服务器为什么这么便宜 软件开发山东 网络安全竞技塞 软件开发不合理的人员结构 河南烈焰网络技术有限公司产品 华为服务器修改网口名 怎么确认数据库有没有这张表 盘点最好玩的服务器我的世界 如何确定数据库的通讯时间 学术文献数据库可用来干什么 服务器跟交换机怎么配合 数据库字段太大用什么字段类型 数据库基础及应用模拟题1
0