调度平台YYSchedule-细节-taskmanager之生成id并保证唯一性

一、介绍

     在调度平台中,下发任务的单位有三种,分别是mission,job,task,因此我们在代码中也必须生成相应格式的missionId,jobId以及taskId。

    对于代码生成id,我们使用的是+1的方式来进行生成,也就是说,假如现在的jobId为xxxx111,那么我们在生成下一个job时,赋予其的jobId应该为xxxx112,这部分应该很好理解,我们第一反应应该就是直接jobId++或++jobId。

二、问题   

   但实际上在Java语言中,++i和i++并不是线程安全的,我们来考虑下面这种情况:

    假设现在的线程A、B、C同时在生成jobId,现在的jobId为xxxx111,A,B线程同时查询了jobId,在此基础上生成了新的job的id值,此时便会出现两个xxxx112。导致jobId丢失唯一性。由此,我们产生了下面这个问题。

    问题:如何在多线程的情况下保证生成Id不会重复?

    

 三、预备知识:AtomicInteger,一个提供原子操作的Integer的类。使用该类能保证线程安全,其使用方法如下:

//获取当前的值
 public final int get()

 //取当前的值,并设置新的值
  public final int getAndSet(int newValue)
 
 //获取当前的值,并自增
  public final int getAndIncrement() 
 
 //获取当前的值,并自减 
 public final int getAndDecrement()

 //获取当前的值,并加上预期的值 
 public final int getAndAdd(int delta)

四、解决方案:

1、使用单例模式。(spring注入自带单例模式)

需要注意的是,spring中的单例模式是指:对于每一个IOC容器,它只会生成唯一的实例

也就是说,我们必须只生成一个applicationContext,然后所有操作都在这个applicationContext下

详见我的上一篇博客“新调度平台-5

2、使用ConcurrentHashMap

关键代码如下截图所示:

五、具体代码:

1、生成missionId的MissionMapper:

missionId=userId + missionCount(6位)组成

 
package com.YYSchedule.task.mapper;

import java.text.DecimalFormat;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.YYSchedule.common.mybatis.pojo.UserBasic;
import com.YYSchedule.store.service.UserBasicService;

@Component("MissionMapper")
@Scope("singleton")
public class MissionMapper
{
	@Autowired
	private UserBasicService userBasicService;
	
	/**
	 * Map<UserId, MissionCount>
	 */
	private Map<Integer, AtomicInteger> missionCountMap = new ConcurrentHashMap<Integer, AtomicInteger>();
	
	private MissionMapper(){
	}
	
	public synchronized Map<Integer, AtomicInteger> getMissionCountMap()
	{
		return missionCountMap;
	}

	
	/**
	 * init mission count map
	 * @param missionType
	 * @param missionCount
	 */
	public synchronized void initMissionCountMap(Integer userId, Integer missionCount) {
		if (missionCountMap.get(userId) == null) {
			missionCountMap.put(userId, new AtomicInteger(missionCount));
		}
	}
	
	/**
	 * get missionCount
	 * 
	 * @param userId
	 * @return
	 */
	public synchronized int getMissionCount(Integer userId)
	{
		if(missionCountMap.get(userId) != null)
		{
			return missionCountMap.get(userId).get();
		}
		else
		{
			return 0;
		}
	}
	
	/**
	 * increase and get mission count
	 * 
	 * @param userId
	 * @return
	 */
	public synchronized int increaseAndGetMissionCount(Integer userId) 
	{
		int missionCount = missionCountMap.get(userId).incrementAndGet(); 

		// update mission count in database
		UserBasic userBasic = new UserBasic();
		userBasic.setUserId(userId);
		userBasic.setMissionCount(missionCount);
		
		System.out.println(missionCount);
		
		userBasicService.updateUserBasic(userBasic);
		return missionCount;
	}
	
	
	/**
	 * generate new mission id
	 * 
	 * @param 
	 * @return
	 */
	public synchronized long generateMissionId(Integer userId) {
		
		StringBuilder sbuilder = new StringBuilder();
		
		sbuilder.append(userId);
		
		int missionCount = increaseAndGetMissionCount(userId); 
		sbuilder.append(new DecimalFormat("0000000").format(missionCount));
		
		return Long.parseLong(sbuilder.toString());
	}
}


2、生成jobId的JobMapper:

jobId=missionId + jobCount(2位)组成

package com.YYSchedule.task.mapper;

import java.text.DecimalFormat;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.YYSchedule.common.mybatis.pojo.MissionBasic;
import com.YYSchedule.store.service.MissionBasicService;

@Component("JobMapper")
@Scope("singleton")
public class JobMapper
{
	@Autowired
	private MissionBasicService missionBasicService;
	
	/**
	 * Map<MissionId, JobCount>
	 */
	private Map<Integer, AtomicInteger> jobCountMap = new ConcurrentHashMap<Integer, AtomicInteger>();
	
	private JobMapper(){
	}
	
	public synchronized Map<Integer, AtomicInteger> getJobCountMap()
	{
		return jobCountMap;
	}

	
	/**
	 * init job count map
	 * @param jobType
	 * @param jobCount
	 */
	public synchronized void initJobCountMap(Integer missionId, Integer jobCount) {
		if (jobCountMap.get(missionId) == null) {
			jobCountMap.put(missionId, new AtomicInteger(jobCount));
		}
	}
	
	/**
	 * get jobCount
	 * 
	 * @param missionId
	 * @return
	 */
	public synchronized int getJobCount(Integer missionId)
	{
		if(jobCountMap.get(missionId) != null)
		{
			return jobCountMap.get(missionId).get();
		}
		else
		{
			return 0;
		}
	}
	
	/**
	 * increase and get job count
	 * 
	 * @param missionId
	 * @return
	 */
	public synchronized int increaseAndGetJobCount(Integer missionId) 
	{
		int jobCount = jobCountMap.get(missionId).incrementAndGet(); 

		// update job count in database
		MissionBasic missionBasic = new MissionBasic();
		missionBasic.setMissionId(missionId);
		missionBasic.setJobCount(jobCount);
		
		
		missionBasicService.updateMissionBasic(missionBasic);
		return jobCount;
	}
	
	
	/**
	 * generate new job id
	 * 
	 * @param 
	 * @return
	 */
	public synchronized int generateJobId(Integer missionId) {
		
		StringBuilder sbuilder = new StringBuilder();
		
		sbuilder.append(missionId);
		
		int jobCount = increaseAndGetJobCount(missionId); 
		sbuilder.append(new DecimalFormat("00000").format(jobCount));
		
		return Integer.parseInt(sbuilder.toString());
	}
}

猜你喜欢

转载自blog.csdn.net/bintoYu/article/details/80723943