springboot之几种同步,线程安全处理的方法

springboot之几种同步,线程安全处理的方法,第1张

在一些公共资源的处理上,经常会出现对公共资源的争夺使用权限的问题,以及对数据库处理时,容易出现线程安全的问题,比如对数据 *** 作时的一致性,可见性等等。 

这时候,为了避免这样的问题,一般的处理方式是当某一个公共资源在被某一个线程调用时,把这个公共资源(即代码块)锁住。 

下面先大概介绍两种简单的同步方法: 

注:同步是一种高开销的 *** 作,因此应该尽量减少同步的内容。 

没有必要同步整个方法,只使用synchronized代码块同步关键代码即可。 

1.同步方法 

即有synchronized关键字修饰的方法。 

由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 

内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。 

代码如: 

public synchronized void demo(){} 

注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类 

2.同步代码块 

即有synchronized关键字修饰的语句块。 

被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 

代码如: 

synchronized(object){ 

lock.lock()       try {

System.out.println("已锁住")           for (int i=0i<10i++) {   //放大代码块执行完成的时间,便于观察

System.out.println(i)               try {

System.out.println(Thread.currentThread().getName()+ "休眠5秒!")

Thread.sleep(5000)//放大代码块执行完成的时间,便于观察

} catch (InterruptedException e) {

e.printStackTrace()

}

}

}finally {            lock.unlock()

System.out.println("解锁")

}12345678910111213141516

当代码块被锁住后,有其它的线程来调用被锁住的线程时,必须先等待上一个线程使用完之后,释放资源,才能继续执行。 

以上两种方法很简单,就不过多的写了,但是这两种方法在使用时,有以下几个问题: 

(1). 当公共资源被占用时,其它线程必须等待资源被释放后才能执行,这种场景适用于对数据库的 *** 作,保证其数据的原子性。当被抢占的资源是即时的公共资源,只有在某一时刻抢到才有意义,比如说在公共场所对空调的控制,大家都要争夺对空调的控制权,但如果是用上述的方法,对空调的控制会按照发出请求的时间,依次执行,那就没有意义了。所以这种场景适合只执行最先抢到资源的线程,在资源被占用时,杀死其它的请求线程。这种情况用以下的方法实现 

3. Semaphore并发包 

Semaphore是基于计数的信号量,它可以设定一个资源的总数量,基于这个总数量,多线程竞争获取许可信号,做自己的申请后归还,超过总数量后,线程申请许可,信号将会被阻塞。等到有资源时,继续执行。 

下面在springboot中实现:

@Contorller public class Controller(){

Semaphore semaphore=new Semaphore(1) //定义资源的总数量

@GetMapping("/userInfo/request")

@ResponseBody    public String Resquest(){        int availablePermits=semaphore.availablePermits()//可用资源数

if(availablePermits>0){

System.out.println("抢到资源")

}else{

System.out.println("资源已被占用,稍后再试")           return "Resource is busy!"

}        try {

semaphore.acquire(1) //请求占用一个资源

System.out.println("资源正在被使用")

Thread.sleep(30000)//放大资源占用时间,便于观察

} catch (InterruptedException e) {

e.printStackTrace()

}finally{

semaphore.release(1)//释放一个资源

}        return "Success"

}

}123456789101112131415161718192021222324252627

当只有一个资源请求时,效果如下: 

 

程序运行完之后,页面会返回Success 

当有多个线程同时请求资源时,效果如下: 

先获得资源的线程会在30秒之后显示success,后面请求的线程会直接返回 

 

 

 

大致的思路和框架就是这样,可根据自己的需要进行修改。

1、controller本身就是单例的,非线程安全,多线程会共用对象

2、controller不要涉及业务层,从其属性来看,控制层来连接请求触发服务

3、根据需求,两种方法都可行,只要不在controller层处理业务;

4、如果三个方法都是需要返回数据的,建议各自写各自的controller层,清晰明白;其实,如果三个方法业务性质一样,也可以封装起来,通过参数判断具体执行那部分代码

网上有很多教程,还是做一个备忘。

首先还是标准的SpringBoot程序,但是要 implements CommandLineRunner 接口。增加之后,会自动提示实现run方法,如下

此时就可以用标准的命令行方式执行该方法,如下

以上,args[0]会是UserInfoSupplier,args[1]会是3。

在Application类中可以使用Autowire,但是注意这里并不会自动结束。比如你想打印一行语句就执行完了,这是做不到的。那么怎么实现呢?其实非常简单。

因为这个类存在main方法,所以在其中调用run方法时增加close方法调用即可。

这样的话,运行完自定义的run方法后,就会退出线程。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8055334.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-13
下一篇 2023-04-13

发表评论

登录后才能评论

评论列表(0条)

保存