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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/east123321/article/details/78954060

Java中对线程安全的处理有很多的方法,不同的情景要选择不同的方法来实现,对并发处理的整体知识架构请参考另外一篇博文:点击查看
以下只是粗糙的介绍部分
在一些公共资源的处理上,经常会出现对公共资源的争夺使用权限的问题,以及对数据库处理时,容易出现线程安全的问题,比如对数据操作时的一致性,可见性等等。
这时候,为了避免这样的问题,一般的处理方式是当某一个公共资源在被某一个线程调用时,把这个公共资源(即代码块)锁住。
下面先大概介绍两种简单的同步方法:
注:同步是一种高开销的操作,因此应该尽量减少同步的内容
没有必要同步整个方法,只使用synchronized代码块同步关键代码即可。
1.同步方法
即有synchronized关键字修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
代码如:
public synchronized void demo(){}
注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
2.同步代码块
即有synchronized关键字修饰的语句块。
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
代码如:
synchronized(object){
}

        lock.lock();
        try {
            System.out.println("已锁住");
            for (int i=0;i<10;i++) {   //放大代码块执行完成的时间,便于观察
                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("解锁");
        }

当代码块被锁住后,有其它的线程来调用被锁住的线程时,必须先等待上一个线程使用完之后,释放资源,才能继续执行。
以上两种方法很简单,就不过多的写了,但是这两种方法在使用时,有以下几个问题:
(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";
	}

 }
 

当只有一个资源请求时,效果如下:
这里写图片描述
程序运行完之后,页面会返回Success
当有多个线程同时请求资源时,效果如下:
先获得资源的线程会在30秒之后显示success,后面请求的线程会直接返回
这里写图片描述
这里写图片描述
这里写图片描述
大致的思路和框架就是这样,可根据自己的需要进行修改。

展开阅读全文

没有更多推荐了,返回首页