SpringBoot开发中的一些小细节(十)

SpringBoot开发中的一些小细节(十)

2019, Mar 29    

前言

本文主要记录最近工作中关于开发中的一些小技巧以及感悟

小细节

权重转换百分比的问题

在工作中需要将各个对象所对应的权重转换成百分比,并且要求最后转换出来的百分比,同一类型的相加必须为百分之百,解决思路主要如下

  • 将各个类型的对象都分别分类
  • 算出各个类型的总权重
  • 算出每个对象在自己类型下的所占百分比
  • 判断每个类型下的对象百分比相加是否等于100
  • 在List处理的时候,可以将List分割成当前类型,和非当前类型 其中需要注意的是,在算百分比的时候,*100应该写在分子

eg: //这样会一直为0,是错误的 //原因是运算符是从左往右计算 //前面除法算出来之后会直接去尾,不足1就是0,所以最后乘以100结果还是0 percent / totalWeight * 100 //这样是正确的 percent * 100 / totalWeight

code:

    private List<GreyDestination> getDestinationsPercent(List<GreyDestination> tempDestinations) {
        HashMap<String, Integer> serviceAndTotalWeight = new HashMap<>();
        HashMap<String, Integer> serviceAndCount = new HashMap<>();
        getServiceWeightAndCount(tempDestinations, serviceAndTotalWeight, serviceAndCount);
        List<GreyDestination> finalDestinations = tempDestinations.stream().map(
                destination -> {
                    String service = destination.getService();
                    Integer count = serviceAndCount.get(service);
                    if (count == 1) {
                        destination.setPercent(100);
                    } else {
                        Integer totalWeight = serviceAndTotalWeight.get(service);
                        if (totalWeight == 0) {
                            totalWeight = 1;
                        }
                        destination.setPercent(destination.getWeight() * 100 / serviceAndTotalWeight.get(service));
                    }
                    return destination;
                }
        ).collect(Collectors.toList());

        for (String service : serviceAndCount.keySet()) {
            if (serviceAndCount.get(service) > 1) {
                List<GreyDestination> collectService = finalDestinations.stream().filter(destination -> destination.getService().equals(service)).collect(Collectors.toList());
                List<GreyDestination> collectRest = finalDestinations.stream().filter(destination -> !destination.getService().equals(service)).collect(Collectors.toList());

                Integer firstPercet= 100;
                for (int i = 1; i < collectService.size(); i++) {
                    firstPercet = firstPercet-collectService.get(i).getPercent();
                }
                GreyDestination firstDestination = collectService.get(0);
                firstDestination.setPercent(firstPercet);
                collectService.set(0, firstDestination);
                collectService.addAll(collectRest);
                finalDestinations=collectService;
            }
        }
        return finalDestinations;
    }

    private void getServiceWeightAndCount(List<GreyDestination> tempDestinations, HashMap<String, Integer> serviceAndTotalWeight, HashMap<String, Integer> serviceAndCount) {
        for (GreyDestination tempDestination : tempDestinations) {
            String service = tempDestination.getService();
            Integer weight = tempDestination.getWeight();
            //存储每个service的count
            if (serviceAndCount.containsKey(service)) {
                serviceAndCount.put(service, serviceAndCount.get(service) + 1);
            } else {
                serviceAndCount.put(service, 1);
            }
            //增加每个Service的total weight
            if (serviceAndTotalWeight.containsKey(service)) {
                serviceAndTotalWeight.put(service, serviceAndTotalWeight.get(service) + weight);
            } else {
                serviceAndTotalWeight.put(service, weight);
            }
        }
    }

公共基础父类

例如 分页模块,应该在父类定制一个最简单的模型,然后在各个业务Service中继承的时候,分别定制化各个服务中特有的特征,已达到方法真正的可扩展性和可复用性。

单例模式

这个常见的设计模式,主要是用来保证这个对象,只会被实例化一次,比如在线程池中的时候

泛型

三种类型
  • 泛型接口(写在接口名之后)

      public interface List<E> extends Collection<E>
    
  • 泛型类(将泛型写在类名之后)

      class Test<T>{ 
          private T data;
      }
    
  • 泛型方法(将泛型写在方法返回值之前)

      public static <T extends Comparable> void sort(T[] arr, int left, int right)
    
实例code
	package QuickSort;
	import com.google.common.base.Joiner;
	/**
	 * Created by ymk on 2019/3/29.
	 * 这个类主要是用来实现快速排序的
	 */
	public class QuickSort {

	    public static <T extends Comparable> void sort(T[] arr, int left, int right) {
	        if (left >= right)
	            return;
	        int i = left, j = right;
	        T key = arr[i];

	        while (i < j) {
	            while (arr[j].compareTo(key) >= 0 && i < j) {
	                j--;
	            }
	            //j找到第一个比key小的值,ij交换值
	            swap(arr,i,j);
	            while (arr[i].compareTo(key) <= 0 && i < j) {
	                i++;
	            }
	            //i找到第一个比key大的值,ij交换值
	            swap(arr,i,j);
	        }
	        //开始递归
	        sort(arr,left,i);
	        sort(arr,i+1,right);
	    }

	    public static <T> void swap(T[] arr, int i, int j) {
	        T temp = arr[i];
	        arr[i] = arr[j];
	        arr[j] = temp;
	    }

	    public static void main(String[] args) {
	        Integer[] arr={1,2,325,52,34,5346,23,23,56,74,34,634,74,34};
	        Joiner joiner = Joiner.on(",");
	        System.out.println(joiner.join(arr));
	        sort(arr,0,arr.length-1);
	        System.out.println(joiner.join(arr));

	    }

	}

分布式锁的问题

最近工作中的后台服务,部署在了测试环境中的两个节点上,然后执行同一个定时任务的时候,虽然都写了在更新之前先删除库中信息,然后再将新的数据入库的操作,但是实际部署之后,还是会出现数据的冗余,原因应该是在某一瞬间,两个服务同时删除了库,然后同时插入了相同的数据。虽然过一段时间后就数据再次就正常了,但是这还是一个问题

Java分布式锁

可以使用分布式锁,将锁放在redis当中(分布式问题之所以复杂,就是因为网络延迟和网络不可靠的问题)setnx ,get等等(有可能会出现阻塞的情况,比如在操作的时候宕机了,来不及释放),具体有机会的时候,实践一下吧

顺便复习一下死锁的四个必要条件:

  • 排他性
  • 请求和保持资源
  • 不剥夺资源
  • 形成等待环路