线程的同步

本文详细介绍了Java中线程同步的基本概念与实现方法,包括如何使用synchronized关键字进行同步控制,以及同步方法与同步代码块的区别。通过具体示例演示了同步机制在多线程环境下确保数据一致性的关键作用。
Java线程:线程的同步-同步方法
 
线程的同步是保证多线程安全访问竞争资源的一种手段。
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?
 
在本文之前,请参阅《 Java线程:线程的同步与锁》,本文是在此基础上所写的。
 
对于同步,在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。
 
synchronized关键字使用说明
synchronized只能标记非抽象的方法,不能标识成员变量。
 
为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。
 
 
/** 
* Java线程:线程的同步 

* @author leizhimin 2009-11-4 11:23:32 
*/
 
public  class Test { 
         public  static  void main(String[] args) { 
                User u =  new User( "张三", 100); 
                MyThread t1 =  new MyThread( "线程A", u, 20); 
                MyThread t2 =  new MyThread( "线程B", u, -60); 
                MyThread t3 =  new MyThread( "线程C", u, -80); 
                MyThread t4 =  new MyThread( "线程D", u, -30); 
                MyThread t5 =  new MyThread( "线程E", u, 32); 
                MyThread t6 =  new MyThread( "线程F", u, 21); 

                t1.start(); 
                t2.start(); 
                t3.start(); 
                t4.start(); 
                t5.start(); 
                t6.start(); 
        } 


class MyThread  extends Thread { 
         private User u; 
         private  int y = 0; 

        MyThread(String name, User u,  int y) { 
                 super(name); 
                 this.u = u; 
                 this.y = y; 
        } 

         public  void run() { 
                u.oper(y); 
        } 


class User { 
         private String code; 
         private  int cash; 

        User(String code,  int cash) { 
                 this.code = code; 
                 this.cash = cash; 
        } 

         public String getCode() { 
                 return code; 
        } 

         public  void setCode(String code) { 
                 this.code = code; 
        } 

         /** 
         * 业务方法 
         * @param x 添加x万元 
         */
 
         public  synchronized  void oper( int x) { 
                 try { 
                        Thread.sleep(10L); 
                         this.cash += x; 
                        System.out.println(Thread.currentThread().getName() +  "运行结束,增加“" + x +  "”,当前用户账户余额为:" + cash); 
                        Thread.sleep(10L); 
                }  catch (InterruptedException e) { 
                        e.printStackTrace(); 
                } 
        } 

        @Override 
         public String toString() { 
                 return  "User{" + 
                                 "code='" + code + '\'' + 
                                 ", cash=" + cash + 
                                '}'; 
        } 
}
 
输出结果:
线程A运行结束,增加“20”,当前用户账户余额为:120 
线程F运行结束,增加“21”,当前用户账户余额为:141 
线程E运行结束,增加“32”,当前用户账户余额为:173 
线程C运行结束,增加“-80”,当前用户账户余额为:93 
线程B运行结束,增加“-60”,当前用户账户余额为:33 
线程D运行结束,增加“-30”,当前用户账户余额为:3 

Process finished with exit code 0
 
 
反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下:
线程A运行结束,增加“20”,当前用户账户余额为:61 
线程D运行结束,增加“-30”,当前用户账户余额为:63 
线程B运行结束,增加“-60”,当前用户账户余额为:3 
线程F运行结束,增加“21”,当前用户账户余额为:61 
线程E运行结束,增加“32”,当前用户账户余额为:93 
线程C运行结束,增加“-80”,当前用户账户余额为:61 

Process finished with exit code 0
 
很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。
 
可见同步的重要性。
 
 
注意:
通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于java.lang.Object类。
 
void notify()    
                    唤醒在此对象监视器上等待的单个线程。    
void notifyAll()    
                    唤醒在此对象监视器上等待的所有线程。    
void wait()    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。    
void wait( long timeout)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。    
void wait( long timeout,  int nanos)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
 
结合以上方法,处理多线程同步与互斥问题非常重要,著名的生产者-消费者例子就是一个经典的例子,任何语言多线程必学的例子。


Java线程:线程的同步-同步块
 
对于同步,除了同步方法外,还可以使用同步代码块,有时候同步代码块会带来比同步方法更好的效果。
 
追其同步的根本的目的,是控制竞争资源的正确的访问,因此只要在访问竞争资源的时候保证同一时刻只能一个线程访问即可,因此Java引入了同步代码快的策略,以提高性能。
 
在上个例子的基础上,对oper方法做了改动,由同步方法改为同步代码块模式,程序的执行逻辑并没有问题。
 
 
/** 
* Java线程:线程的同步-同步代码块 

* @author leizhimin 2009-11-4 11:23:32 
*/
 
public  class Test { 
         public  static  void main(String[] args) { 
                User u =  new User( "张三", 100); 
                MyThread t1 =  new MyThread( "线程A", u, 20); 
                MyThread t2 =  new MyThread( "线程B", u, -60); 
                MyThread t3 =  new MyThread( "线程C", u, -80); 
                MyThread t4 =  new MyThread( "线程D", u, -30); 
                MyThread t5 =  new MyThread( "线程E", u, 32); 
                MyThread t6 =  new MyThread( "线程F", u, 21); 

                t1.start(); 
                t2.start(); 
                t3.start(); 
                t4.start(); 
                t5.start(); 
                t6.start(); 
        } 


class MyThread  extends Thread { 
         private User u; 
         private  int y = 0; 

        MyThread(String name, User u,  int y) { 
                 super(name); 
                 this.u = u; 
                 this.y = y; 
        } 

         public  void run() { 
                u.oper(y); 
        } 


class User { 
         private String code; 
         private  int cash; 

        User(String code,  int cash) { 
                 this.code = code; 
                 this.cash = cash; 
        } 

         public String getCode() { 
                 return code; 
        } 

         public  void setCode(String code) { 
                 this.code = code; 
        } 

         /** 
         * 业务方法 
         * 
         * @param x 添加x万元 
         */
 
         public  void oper( int x) { 
                 try { 
                        Thread.sleep(10L); 
                         synchronized ( this) { 
                                 this.cash += x; 
                                System.out.println(Thread.currentThread().getName() +  "运行结束,增加“" + x +  "”,当前用户账户余额为:" + cash); 
                        } 
                        Thread.sleep(10L); 
                }  catch (InterruptedException e) { 
                        e.printStackTrace(); 
                } 
        } 

        @Override 
         public String toString() { 
                 return  "User{" + 
                                 "code='" + code + '\'' + 
                                 ", cash=" + cash + 
                                '}'; 
        } 
}
 
线程E运行结束,增加“32”,当前用户账户余额为:132 
线程B运行结束,增加“-60”,当前用户账户余额为:72 
线程D运行结束,增加“-30”,当前用户账户余额为:42 
线程F运行结束,增加“21”,当前用户账户余额为:63 
线程C运行结束,增加“-80”,当前用户账户余额为:-17 
线程A运行结束,增加“20”,当前用户账户余额为:3 

Process finished with exit code 0
 
注意:
在使用synchronized关键字时候,应该尽可能避免在synchronized方法或synchronized块中使用sleep或者yield方法,因为synchronized程序块占有着对象锁,你休息那么其他的线程只能一边等着你醒来执行完了才能执行。不但严重影响效率,也不合逻辑。
同样,在同步程序块内调用yeild方法让出CPU资源也没有意义,因为你占用着锁,其他互斥线程还是无法访问同步程序块。当然与同步程序块无关的线程可以获得更多的执行时间。
 

内容概要:本文提出了一种基于融合鱼鹰算法和柯西变异的改进麻雀优化算法(OCSSA),用于优化变分模态分解(VMD)的参数,进而结合卷积神经网络(CNN)与双向长短期记忆网络(BiLSTM)构建OCSSA-VMD-CNN-BILSTM模型,实现对轴承故障的高【轴承故障诊断】基于融合鱼鹰和柯西变异的麻雀优化算法OCSSA-VMD-CNN-BILSTM轴承诊断研究【西储大学数据】(Matlab代码实现)精度诊断。研究采用西储大学公开的轴承故障数据集进行实验验证,通过优化VMD的模态数和惩罚因子,有效提升了信号分解的准确性与稳定性,随后利用CNN提取故障特征,BiLSTM捕捉时间序列的深层依赖关系,最终实现故障类型的智能识别。该方法在提升故障诊断精度与鲁棒性方面表现出优越性能。; 适合人群:具备一定信号处理、机器学习基础,从事机械故障诊断、智能运维、工业大数据分析等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①解决传统VMD参数依赖人工经验选取的问题,实现参数自适应优化;②提升复杂工况下滚动轴承早期故障的识别准确率;③为智能制造与预测性维护提供可靠的技术支持。; 阅读建议:建议读者结合Matlab代码实现过程,深入理解OCSSA优化机制、VMD信号分解流程以及CNN-BiLSTM网络架构的设计逻辑,重点关注参数优化与故障分类的联动关系,并可通过更换数据集进一步验证模型泛化能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值