java多线程处理高并发问题
java多线程简单处理高并发问题
在程序应用中,用户或者请求达到一定数量,避免不了出现并发请求,由于每次调用一个接口必须在得到返回时才会结束,如果该接口的业务相对复杂,则有可能多个用户调用一个接口时将会卡顿。
下面将介绍一种巧妙并且十分简单的方式来解决这种问题。
请求写入内存
我们可以将每次的请求封装为对象写入内存里。
@Getter
@Setter
private static class CallVo{//请求对象
private Long param1;//参数1
private Integer param2;//参数2
}
private List<CallVo> callVoList = new ArrayList<>();//请求对象列表
/**
* 接口调用
* @param callVo
* @return
*/
@Transactional
@RequestMapping(value = "/call",method = {RequestMethod.POST})
public void call(@RequestBody CallVo callVo){
synchronized (syncObject) {
callVoList.add(callVo);//将请求对象写入内存
}
}
多线程处理
创造一个线程让他一直读取内存里的数据,如果请求对象的集合长度为0,证明没有请求,如果集合里有数据,则将此次请求的对象移除集合,并获取该次请求的参数,根据相应的业务来进行处理。
这样就达到了化同步为异步的目的,简单解决了高并发的问题。
private Thread thread;
private final Object syncObject = new Object(); // 同步对象
private volatile boolean runnable;
@Override
public void run() {
while (runnable){
try {
if (callVoList.size() == 0) {//集合长度为0,证明没有请求
Thread.sleep(1000);
continue;
}
CallVo callVo;
synchronized (syncObject) {
callVo = callVoList.remove(0);
}
Long param1 = callVo.getStationId();
Integer param2 = callVo.getCallType();
//业务处理
System.out.println(param1+"---"+param2);
}catch (Exception e){
logger.error("接口调用异常:", e);
}
}
}
完整代码
@RestController
@Slf4j
@RequestMapping("/erpRemote")
public class ErpRemoteController extends BaseController implements DisposableBean, Runnable{
ErpRemoteController(){
callVoList = new ArrayList<>();
runnable = true;
thread = new Thread(this);
thread.start();
}
/**
* 接口调用
* @param callVo
* @return
*/
@Transactional
@RequestMapping(value = "/call",method = {RequestMethod.POST})
public GeneralResponse call(@RequestBody CallVo callVo){
synchronized (syncObject) {
callVoList.add(callVo);//将请求对象写入内存
}
return GeneralResponse.success(null);
}
@Getter
@Setter
private static class CallVo{//请求对象
private Long param1;//参数1
private Integer param2;//参数2
}
private List<CallVo> callVoList;
private Thread thread;
private final Object syncObject = new Object(); // 同步对象
private volatile boolean runnable;
@Override
public void run() {
while (runnable){
try {
if (callVoList.size() == 0) {//集合长度为0,证明没有请求
Thread.sleep(1000);
continue;
}
CallVo callVo;
synchronized (syncObject) {
callVo = callVoList.remove(0);
}
Long param1 = callVo.getStationId();
Integer param2 = callVo.getCallType();
//业务处理
System.out.println(param1+"---"+param2);
}catch (Exception e){
logger.error("接口调用异常:", e);
}
}
}
@Override
public void destroy() {
runnable = false;
}
}
局限性
由于化同步为异步,每次请求接口的返回值时唯一的,因此该方法只适用于请求方不需要返回时的场景。