Задача ScheduledExecutorService будет выполняться многопоточным - PullRequest
0 голосов
/ 13 ноября 2018

Это делает меня действительно любопытным. Есть кнопка, которая отправляет простой пост-запрос с помощью ajax на страницу JSP, и я использую метод RESTFUL для обработки этого запроса, но этот метод будет выполняться два или три раза. происходит только в CentOS 7.3, на моем ноутбуке я использую windows10, многопоточность не произойдет. Я искал в Google, но ничего полезного был найден. Вот коды:

asset.jsp:

<button class="btn btn-default btn-sm" title="allDoMi">
      <i class="fa fa-arrow-down">allDoMi</i>
</button>
$("button[title='allDoMi']").click(function () {
    var dataparam = "version=1";
    if (!confirm('confirm all DoMi?'))
        return;
    //ajax request
    $.ajax({
        contentType: "application/json",
        url: serviceurl.baseurl + "/asset/doMiAction",
        data: dataparam,
        beforeSend: function () {
             //do nothing
        },
        error: function () {
             //do nothing
        },
        success: function (info) {
             //do nothing    
        }
    });
});

Asset.java

@Service
@Path("/asset")
public class AssetRest {
    @Path("/doMiAction")
    @POST
    @Produces({ MediaType.APPLICATION_JSON, 
                                 MediaType.APPLICATION_XML })
    public RestfulResult doMiAction(@FormParam("version") String 
          version) {
          logger.info("doMiAction method began....");
          //package data for duMiSyncDtos,here only for test
          List<DuMiSyncDto> duMiSyncDtos =new List<>();
          //this url is for http simulation using HttpURLConnection
          final String dumiUrl = "http://someip/someurl";
          final Map<String, List<DuMiSyncDto>> map; 
          //only continue when list is not empty
          if (!duMiSyncDtos.isEmpty()) {
             //this method used for sync data in a certain order
             map = groupList(duMiSyncDtos);
             SortedSet<String> ss = new TreeSet<>(map.keySet());
             final Iterator<String> iter = ss.iterator();
             final ScheduledExecutorService ticker = Executors.newSingleThreadScheduledExecutor();
             logger.info("NEW A SINGLETHREADSCHEDULEDEXECUTOR");
             //retrieve data from a .property file,I set it 20000,therefore the job will be executed in every 20 seconds
             final int DELAY = NumberUtils.toInt(WebUtils.getConfigValue("dumi.delay"));
             ticker.scheduleWithFixedDelay(new Runnable() {
             private int count;
             public void run() {
                logger.info("BEGIN RUN METHOD:"+System.identityHashCode(AssetRest.this));
                if(iter.hasNext()) {
                    try {
                        List<DuMiSyncDto> value = map.get(iter.next());
                        //this method used for simulating a httprequest using HttpURLConnection to invoke a remote service to get the result info which forms in a JSON string format
                        String resultmsg = getDuMiReturnMessage(dumiUrl,value);
                        if(resultmsg!=null && !resultmsg.contains("\"code\":\"0000\"")) {
                            logger.info("Return code is "+resultmsg+",the sync work will be terminated.");
                            ticker.shutdown();
                            return;
                        }
                        //this method used for showing some useful infomation on the console using log4j
                        showSyncInfomation(value);
                        //this method used for count how many items have been synchronized successfully
                        int currentcount = getSyncCount(resultmsg);
                        count += currentcount ;
                        logger.info("current sync  data:"+currentcount+",summing data"+count+"");
                    } catch (Exception e) {
                        logger.error("method[doMiAction]...executing schedule:",e);
                    }
                } else {
                    ticker.shutdown();
                }
            }
        }, 0, DELAY, TimeUnit.MILLISECONDS);
    }
}

После того, как я нажму кнопку, вся информация журнала будет отображаться на консоли Putty два или три раза, но я нажимал эту кнопку только ОДИН РАЗ! Я проверял несколько раз, это произойдет, но в Windows включен Мой ноутбук, это не произойдет вообще. Вот деталь может помочь: ранее реализация для выполнения по времени не была такой, она была написана как:

for(DuMiSyncDto dto:duMiSyncDtoList){
    //do the business code
    Thread.sleep(20000);
}

Поскольку существует синхронизация базы данных от удаленной службы, мне нужно не слишком быстро контролировать интервал между каждыми двумя операциями: выполнять каждые 20 секунд и 100 данных одновременно. В этой ситуации возникает проблема с многопоточностью Я подумал, что это может быть цикл for, который возник, поэтому я изменил способ, используя JDK API, но проблемы все еще были. Так ПОЧЕМУ все это?

--------------------------- первое редактирование ------------------ ------------------------

private int getSyncCount(String resultmsg) {
    int count = 0;
    JSONObject obj = JSONObject.fromObject(resultmsg);
    String message = obj.getString("message");
    if(!WebUtils.isEmpty(message)) {
        String[] arr = message.split(" ");
        if(arr!=null && arr.length>1) {
            count += Integer.parseInt(arr[1].trim());
        }
    }
    logger.info("currentThreadName:"+Thread.currentThread().getName());
    return count;
}

Обратите внимание, в этом методе я записываю имя текущего потока, и оно показывает:

...     
currentThreadName:pool-1-thread-1
currentThreadName:pool-2-thread-1
currentThreadName:pool-3-thread-1
...

при наличии 3 потоков.

...