千家信息网

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

发表于:2024-12-13 作者:千家信息网编辑
千家信息网最后更新 2024年12月13日,本篇内容介绍了"Java线程安全与同步实例分析"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!线程安全
千家信息网最后更新 2024年12月13日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安全错误 数据库的锁怎样保障安全 云服务器丢了怎么办 肃州区网络安全大队在哪 教学软件开发过程依次是 郑州软件开发科技公司地址 mdb如何筛选数据库 计算机网络技术珠海校区 苏州戴尔服务器家用版 江西app软件开发多少钱 软件开发优秀员工自评 手游lol国际服连接服务器错误 关于数据库性能管理的四个阶段 简述计算机网络技术的功能 腾讯云服务器做传奇哪个合适 华南x79能用服务器内存嘛 智能网络技术是学什么的 网络安全的基本要求和目标 哈利波特每个服务器账号不同 邮件服务器更换证书 网构软件开发主要涉及的内容 软件开发培训学校难学吗 郑州软件开发科技公司地址 护苗网络安全课初中 王者荣耀 服务器域名 美国2011年网络安全政策 网络安全收藏备用 征途轩辕版数据库 软件开发适不适合女孩子学 备份服务器管理办法 郑州领航科技网络技术有限公司 软件开发发展趋势总结
0