Надеюсь, что комментарий @BoristheSpider снял ваши сомнения относительно Thread и Runnable.
Относительно синглтона, этот ответ поможет вам понять больше.
Я постараюсь ответить на утверждение от OP
Когда я пытался выполнить этот поток через TaskExecutor много раз, я думаю, что он должен возвращать один и тот же идентификатор потока каждый раз, но, похоже, он возвращает разные результаты.Может ли кто-нибудь объяснить это для меня?
Это похоже на то, что мы используем различных помощников для выполнения какой-то работы, здесь помощники являются потоками, а работа - вашей бизнес-логикой (в MyThread).
Допустим, мыу нас будет только 1 помощник для выполнения нашей задачи, и это займет около 10 секунд времени, и нам нужно выполнить эту работу 3 раза.
Но так как у нас есть только 1 работник, это займет минимум 10 + 10 + 10 =30 секунд, чтобы выполнить свою задачу.
В следующем тестовом классе я добавил сон 30-х годов, чтобы все дочерние потоки могли завершить свою работу до того, как родительские потоки закончат выполнение.
MyThread.java из OP
Добавлены еще некоторыежурналы и сон.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public class MyThread implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(MyThread.class);
@Override
public void run() {
LOGGER.info("Called from thread + " + Thread.currentThread().getId());
LOGGER.info("Thread info+ " + Thread.currentThread().getName());
LOGGER.info("Thread info+ " + Thread.currentThread().getThreadGroup());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@EnableAsync
@Configuration
public class ThreadConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.setThreadNamePrefix("default_task_executor_thread");
executor.initialize();
return executor;
}
}
Тестовый класс
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class DemoApplicationTests {
@Autowired
ApplicationContext applicationContext;
@Autowired
Executor threadPoolTaskExecutor;
@Test
public void test() throws InterruptedException {
MyThread myThread = applicationContext.getBean(MyThread.class);
if (threadPoolTaskExecutor != null) {
threadPoolTaskExecutor.execute(myThread);
threadPoolTaskExecutor.execute(myThread);
threadPoolTaskExecutor.execute(myThread);
Thread.sleep(30000);// 10000 + 10000 + 10000 ^^ for each thread
}
}
}
Вывод:
2019-06-05 12:31:01.549 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Called from thread + 22
2019-06-05 12:31:01.549 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ default_task_executor_thread1
2019-06-05 12:31:01.549 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ java.lang.ThreadGroup[name=main,maxpri=10]
2019-06-05 12:31:11.552 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Called from thread + 22
2019-06-05 12:31:11.552 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ default_task_executor_thread1
2019-06-05 12:31:11.552 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ java.lang.ThreadGroup[name=main,maxpri=10]
2019-06-05 12:31:21.554 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Called from thread + 22
2019-06-05 12:31:21.555 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ default_task_executor_thread1
2019-06-05 12:31:21.555 INFO 68118 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ java.lang.ThreadGroup[name=main,maxpri=10]
Если вы проверитеПриведенная выше конфигурация, поскольку у нас есть только 1 Поток для выполнения Runnable, один и тот же Поток используется для выполнения всех трех вызовов.
Если вы измените Общее количество потоков на два, одновременно два потока будут использоваться для выполненияRunnable (MyThread) аи
как только одна из задач будет выполнена, другая задача будет использовать тот же поток, который был освобожден ранее выполняемым.
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
ВЫХОД:
2019-06-05 12:39:26.163 INFO 68407 --- [xecutor_thread2] com.example.controller.MyThread : Called from thread + 23
2019-06-05 12:39:26.163 INFO 68407 --- [xecutor_thread2] com.example.controller.MyThread : Thread info+ default_task_executor_thread2
2019-06-05 12:39:26.163 INFO 68407 --- [xecutor_thread2] com.example.controller.MyThread : Thread info+ java.lang.ThreadGroup[name=main,maxpri=10]
2019-06-05 12:39:26.163 INFO 68407 --- [xecutor_thread1] com.example.controller.MyThread : Called from thread + 22
2019-06-05 12:39:26.164 INFO 68407 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ default_task_executor_thread1
2019-06-05 12:39:26.164 INFO 68407 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ java.lang.ThreadGroup[name=main,maxpri=10]
2019-06-05 12:39:36.169 INFO 68407 --- [xecutor_thread1] com.example.controller.MyThread : Called from thread + 22
2019-06-05 12:39:36.169 INFO 68407 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ default_task_executor_thread1
2019-06-05 12:39:36.169 INFO 68407 --- [xecutor_thread1] com.example.controller.MyThread : Thread info+ java.lang.ThreadGroup[name=main,maxpri=10]