The java background interface starts another thread to perform other services

Directly post the code, and then explain in detail why:

package com.xxx.testset.service.impl;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 
 * @function xxx Interface implementation class
 * @author Liangjw
 * @date 2019-9-18 02:09:33 PM
 * @version    
 * @since JDK 1.7
 */
public class TestSetServiceImpl extends BizServiceImpl implements TestSetService {    
   
    ExecutorService executorService = Executors.newSingleThreadExecutor();
  
   ...
@Override
public String startTest(String testId) { final String test_Id = testId; Connection con = DBConnectUtil.getConnection(); PreparedStatement pstmt = null,pstmt2 = null; ResultSet resultSet = null; try { Date nowDate = new Date(); final String nowDateStr = DateUtil.dateTransformStr(nowDate, DATE_FORMAT); Map<String, Object> map = new HashMap<String, Object>(); map.put("TEST_ID", testId); //Get detection device set---2020 July 10, 2016:40:44 ljw final List<DataRecord> deviceList = this.getDao().queryForDataSet(STATEMENT_KEY + "selectPdDetectionDevice", map).getResults(); map.put("TEST_STATE", "Testing"); map.put("BEGIN_TIME", nowDateStr); //Obtain the first data in the current tool table and add it to the detection task---2020/07/02 ljw Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("TYPE_NAME", "Inspection vehicle"); List<DataRecord> mechanicsList = this.getDao().queryForDataSet(STATEMENT_KEY + "selectMechanics", parameters).getResults();
       ...
//Start a single thread (in fact, it is to create a thread pool, which is just a single thread pool), and call the algorithm alone to analyze the detection results executorService.execute(new Runnable() { @Override public void run() { //Implement the run method in the Runnable interface. Write the content you want to execute here! Boolean test_flag = true;//In process, "detection" status is true,"Completed is false Connection con = DBConnectUtil.getConnection(); PreparedStatement pstmt = null; ResultSet resultSet = null; String cmdIds = ""; for (int x = 0; x < deviceList.size(); x++) { cmdIds+=deviceList.get(x).getString("CMD_ID") + ","; } cmdIds = cmdIds.substring(0, cmdIds.length() - 1); String sql = "select qp.GUID, qp.PhaseDataA, qp.PDDataA, qp.PhaseDataB, qp.PDDataB, qp.PhaseDataC, qp.PDDataC, tf.TimeFieldDataA, tf.TimeFieldDataB, tf.TimeFieldDataC, qp.ReceiveTime , qp.DeviceID " + "from tb_QPhiData qp left join tb_TimeFieldData tf on qp.GUID = tf.GUID_QPhi where qp.DeviceID in ("+cmdIds+") and qp.ReceiveTime > ? order by qp.ReceiveTime"; int flag = 0;//Identifies the number of algorithm calls String startTime = nowDateStr;//Start detection time String lastTime = null;//Latest time of last query result
            ...
if(!test_flag) { executorService.shutdown(); //Close thread } } // The run() method executes the code part, that's all! }); //Involving thread code, that's all! } catch (Exception e) { e.printStackTrace(); return "Detection failed"; }finally { try { if(resultSet != null){ resultSet.close(); } if(pstmt != null){ pstmt.close(); } if(pstmt2 != null){ pstmt2.close(); } if(con != null){ con.close(); } } catch (SQLException e) { e.printStackTrace(); } } return "Detection successful"; } }

I use ExecutorService to create a thread pool. execute(Runnable) is called when the thread executes and ExecutorService is called when the thread is closed Shutdown() method.

1, ExecutorService introduction

ExecutorService is an interface defined for thread pool in Java util. In concurrent package, methods related to background task execution are defined in this interface:

 

 

There are two implementations of the ExecutorService interface in the Java API, so these two are the specific implementation classes of the java thread pool, click here ):

1. ThreadPoolExecutor
2. ScheduledThreadPoolExecutor

In addition, ExecutorService also inherits the Executor interface (pay attention to distinguish between the Executor interface and the Executors factory class). This interface has only one execute() method. Finally, let's take a look at the whole inheritance tree:

 

 

 

2, Creation of ExecutorService

What kind of ExecutorService instance (i.e. thread pool) to create depends on the specific application scenario. However, Java provides us with an executors factory class, which can help us easily create various types of ExecutorService thread pools. Executors can create the following four types of thread pools:

1. newCachedThreadPool Create a cacheable thread pool. If the length of the thread pool exceeds the processing needs, you can flexibly recycle idle threads. If there is no recyclable thread, you can create a new thread.
2. newFixedThreadPool Create a fixed length thread pool to control the maximum concurrent number of threads. The exceeded threads will wait in the queue.
3. newScheduledThreadPool Create a fixed length routing pool to support regular and periodic task execution.
4. newSingleThreadExecutor Create a singleton thread pool, which will only use a unique worker thread to execute tasks, ensuring that all tasks are in the specified order(FIFO, LIFO, priority)Execution.

Note: Executors is just a factory class. All its methods return instances of ThreadPoolExecutor and ScheduledThreadPoolExecutor.

3, Use of ExecutorService

ExecutorService executorService = Executors.newFixedThreadPool(10);

executorService.execute(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});

executorService.shutdown();

4, ExecutorService execution

ExecutorService has the following execution methods:

- execute(Runnable)
- submit(Runnable)
- submit(Callable)
- invokeAny(...)
- invokeAll(...)

4.1 execute(Runnable)

This method receives a Runnable instance and executes asynchronously. Please see the following example:

ExecutorService executorService = Executors.newSingleThreadExecutor();

executorService.execute(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});

executorService.shutdown();

The problem with this method is that there is no way to know the execution result of the task. If we want to get the execution result of the task, we can pass in a Callable instance (described below).

4.2 submit(Runnable)

The difference between submit(Runnable) and execute(Runnable) is that the former can return a Future object. Through the returned Future object, we can check whether the submitted task has been executed. Please see the following execution example:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});

future.get();  //returns null if the task has finished correctly.

If the task is completed, the future The get () method returns a null. Attention, future The get () method will block.

4.3 submit(Callable)

Similar to submit(Runnable), submit(Callable) also returns a Future object, but in addition, submit(Callable) receives the implementation of a Callable. The call() method in the Callable interface has a return value that can return the execution result of the task, while the run() method in the Runnable interface is void and has no return value. See the following example:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
    System.out.println("Asynchronous Callable");
    return "Callable Result";
}
});

System.out.println("future.get() = " + future.get());

If the task is completed, the future The get () method will return the execution result of the Callable task. Attention, future The get () method will block.

4.4 invokeAny(...)

invokeAny(...) Method receives a Callable collection. Executing this method will not return the Future, but will return the execution result of one of all Callable tasks. This method can't guarantee which task's execution result is returned. It's one of them anyway. See the following example:

ExecutorService executorService = Executors.newSingleThreadExecutor();

Set<Callable<String>> callables = new HashSet<Callable<String>>();

callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 2";
}
});
callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 3";
}
});

String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();

You can try to execute the above code. Each execution will return a result, and the returned result is changed. You may return "Task2" or "Task1" or others.

4.5 invokeAll(...)

invokeAll(...) And invokeAny(...) Similarly, it also receives a Callable set, but the former will return a Future List after execution, which corresponds to the Future object after each Callable task is executed. The following is an example:

ExecutorService executorService = Executors.newSingleThreadExecutor();

Set<Callable<String>> callables = new HashSet<Callable<String>>();

callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 1";
}
});
callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 3";
}
});

List<Future<String>> futures = executorService.invokeAll(callables);

for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}

executorService.shutdown();

5, Shutdown of ExecutorService

After using the ExecutorService, we should close it, otherwise the thread in it will always be running.

For example, if the application is started through the main() method, after the main() exits, if the ExecutorService in the application is not closed, the application will run all the time. This happens because the thread running in ExecutorService prevents the JVM from shutting down.

If we want to close the thread executing in ExecutorService, we can call ExecutorService shutdown() method. After calling the shutdown () method, ExecutorService will not shut down immediately, but it will not receive new tasks until all current threads have completed execution. All tasks submitted before shutdown () execution will be executed.

If we want to close ExecutorService immediately, we can call ExecutorService Shutdownnow() method. This action will skip all tasks in progress and tasks submitted that have not yet been executed. However, it does not guarantee that the tasks being performed may stop or be completed.

Note: the Java thread pool classes ThreadPoolExecutor, ScheduledThreadPoolExecutor and Executors factory classes are described in more detail, click here

 

Reference source, click here

Posted by phoenixx on Mon, 09 May 2022 12:28:48 +0300