Вы не показываете весь свой код, например isCancelled
. Поэтому мы не можем помочь конкретно. Но ваш подход, кажется, не в порядке, так что читайте дальше.
ScheduledExecutorService
Вы не должны пытаться управлять временем обслуживания вашего исполнителя. Если вы звоните Thread.sleep
вместе со службой исполнителя, вы, вероятно, делаете что-то не так.
Не стоит и призывать new Thread
. Весь смысл службы executor состоит в том, чтобы позволить инфраструктуре управлять деталями потоков. Ты слишком много работаешь.
Для повторного вызова задачи используйте ScheduledExecutorService
.
Для получения дополнительной информации см. Oracle Tutorial , class JavaDoc и поиск переполнения стека. К этой теме уже обращались много раз.
Пример приложения
Вот краткий пример.
Используйте служебный класс Executors
для создания пула потоков. Нам нужен только один поток, чтобы вы могли повторно обращаться к базе данных. Глядя на ваш частичный пример кода, я не могу понять, почему вы пытались запустить 5 потоков. Если вы выполняете серию последовательных обращений к базе данных, вам нужен только один поток.
Сделайте ваш Runnable
для вызова базы данных.
package work.basil.example;
import java.sql.Connection;
import java.time.Instant;
public class DatabaseCaller implements Runnable
{
private Connection connection = null;
public DatabaseCaller ( Connection connection )
{
this.connection = connection;
}
@Override
public void run ()
{
// Query the database. Report results, etc.
System.out.println( "Querying the database now. " + Instant.now() );
}
}
ВНИМАНИЕ: Всегда заключайте код метода run
в try catch
, чтобы перехватить любой неожиданный Exception
или Error
(Throwable
). Любой неосторожный бросок, достигающий исполнителя, заставит его прекратить работу. Задание больше не будет запланировано для дальнейших запусков.
Создайте экземпляр Runnable
и запланируйте его повторный запуск.
package work.basil.example;
import java.sql.Connection;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class DbRepeat
{
public static void main ( String[] args )
{
DbRepeat app = new DbRepeat();
app.doIt();
}
private void doIt ()
{
System.out.println( "Starting app. " + Instant.now() );
Connection conn = null; // FIXME: Instantiate a `Connection` object here.
Runnable runnable = new DatabaseCaller( conn );
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
long initialDelay = 0;
long delay = 5;
ScheduledFuture future = ses.scheduleWithFixedDelay( runnable , initialDelay , delay , TimeUnit.SECONDS );
// Let our demo run a few minutes.
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 2 ) ); // Let this app run a few minutes as a demo.
} catch ( InterruptedException e )
{
System.out.println( "Somebody woke up our sleeping thread. Message # 1b296f04-3721-48de-82a8-d03b986a4b55." );
}
// Always shutdown your scheduled executor service. Otherwise its backing thread pool could continue to run, outliving the lifecycle of your app.
ses.shutdown();
System.out.println( "Ending app. " + Instant.now() );
}
}
Обратите внимание, насколько это просто.
- Мы определили задачу в экземпляре
Runnable
объекта.
- Мы создали службу исполнителя, поддерживаемую одним потоком.
- Мы сказали, что сервис должен запускать нашу задачу несколько раз от нашего имени, и мы указали, как часто нужно запускать эту задачу.
- В конце концов, мы сказали службе прекратить планировать дальнейшее выполнение этой задачи и закрыть пул потоков.
Мы ни разу не имели дела с нитями напрямую. Мы позволяем платформе executors обрабатывать все мрачные детали потоков.
Внимание! Вам все равно нужно сделать свой код Runnable
поточно-ориентированным при использовании нескольких потоков. Среда executor чрезвычайно удобна и полезна, но она не волшебная. Чтобы узнать о безопасности потоков и параллелизме в Java, ежегодно читайте эту превосходную книгу: Параллелизм Java на практике Брайана Гетца и др.
При запуске.
Запуск приложения. 2019-03-21T19: 46: 09.531740Z
Запрос к базе данных сейчас. 2019-03-21T19: 46: 09.579573Z
Запрос к базе данных сейчас. 2019-03-21T19: 46: 14.585629Z
...
Запрос к базе данных сейчас. 2019-03-21T19: 47: 59.647485Z
Запрос к базе данных сейчас. 2019-03-21T19: 48: 04.650555Z
Завершение приложения. 2019-03-21T19: 48: 09.579407Z
Пропустить пул соединений
По моему опыту, потребность в пуле соединений с базами данных преувеличена многими людьми. Есть несколько ловушек при использовании пула соединений. И я считаю, что установление соединения с базой данных не так дорого, как утверждают многие, особенно если локально на той же машине.
Так что я предлагаю вам пока пропустить пул соединений. Получите ваш код надежно работает при использовании свежих соединений.
Если позднее вы сможете доказать узкое место в производительности из-за соединений с базой данных, рассмотрите пул. И убедиться, что это действительно помогает. В противном случае вы бы совершили грех преждевременной оптимизации.