코딩마을방범대
Entity에서 암복호화 & JAVA 비동기 처리(Thread) 본문
Entity에서 암복호화 하는 방법
@ColumnTransformer 어노테이션 활용
- read를 통해서 불러올 데이터를 복호화
- write를 통해서 저장할 데이터를 암호화
@ColumnTransformer(
read = "AES_DECRYPT(FROM_BASE64(HP), " + key + "," + iv)" // 칼럼 값을 가져올 때
write = "FUNCTION_ENCRYPT(?)") // 칼럼 값을 쓸 때
private String hp;
JAVA 비동기 처리(Thread)
1. Config 파일을 이용해 스레드풀 사용하기
Executor
- 스레드풀을 구현하기 위한 인터페이스
- Runnable만 개발자가 만들고 생성, 종료, 없애기 작업(일련의 작업)들은 Executors가 담당
스레드 (Thread)
프로세스(process) 내에서 실제로 작업을 수행하는 주체
프로세스(process)
실행 중인 프로그램 (프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것)
스레드 풀 (ThreadPool)
- 스레드를 제한된 개수만큼 정해 놓고 작업 큐에 들어오는 작업들을 하나씩 스레드가 맡아 처리
- 각 작업에 대해 새 스레드를 생성하는 대신 이미 생성된 스레드 풀에 있는 스레드를 재사용
Application 클래스
@EnableAutoConfiguration 혹은 @SpringBootApplication 설정하면,
런타임 시 @Configuration이 설정된 클래스의 Bean 정보를 읽어 들인다.
@SpringBootApplication
public class ApiApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ApiApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
Thread Config 클래스
@Configuration
@EnableAsync
public class threadPoolConfig {
@Bean(name = "testTreadPool")
public Executor threadPoolExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(8);
taskExecutor.setMaxPoolSize(16);
taskExecutor.setQueueCapacity(32);
taskExecutor.setThreadNamePrefix("TestPool-");
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.setAwaitTerminationSeconds(10);
taskExecutor.initialize();
return taskExecutor;
}
}
@EnableAsync | 비동기 처리할 수 있는 기능을 활성화 |
CorePoolSize | 살아있는 스레드 최소 개수 |
MaxPoolSize | 사용할 수 있는 스레드 최대 개수 |
QueueCapacity | 스레드풀에서 사용할 최대 queue 크기 |
ThreadNamePrefix | 스레드이름 설정 |
AwaitTerminationSeconds | 일정 시간(초)이 지나면 강제로 종료 |
KeepAliveSeconds |
스레드 최소 개수를 초과하는 스레드의 유효시간 (default 60초) |
RejectedExecutionHandler |
pool과 queue가 전부 꽉 찬 경우
|
최초의 스레드풀에 CorePoolSize 만큼의 스레드를 만들어 놓고,
전부 사용 중일 경우 QueueCapacity 사이즈의 큐에 작업을 쌓아 놓는다.
Queue 마저 가득 찬 상태라면 MaxPoolSize 만큼 스레드를 추가로 생성하여 동시 처리량을 늘린다.
구현 클래스
위와 같이 설정한 후 아래처럼 Async을 이용해 병렬 사용해주면 된다!
@Async("testTreadPool")
public void test(String targetToken) {
...
}
@EnableAsync 어노테이션을 Application 클래스 위에 붙여 주고,
비동기 방식으로 처리하고 싶은 동기 로직의 메소드 위에 @Async 어노테이션을 붙이면 스레드를 관리하지 않는 문제가 있다.
왜냐하면 @Async의 기본 설정은 SimpleAsyncTaskExecutor를 사용하도록 되어 있는데, 이것은 스레드 풀이 아니고 단순히 스레드를 만들어내는 역할을 하기 때문이다.
2. 사용 중인 메소드 내에서 스레드풀 이용하기
ExecutorService
- 작업(Runnable, Callable) 등록을 위한 인터페이스
( Runnable은 리턴 값이 없으나, Callable은 객체를 리턴할 수 있음 ) - 병렬 작업 시 여러 개의 작업을 효율적으로 처리하기 위해 제공되는 JAVA 라이브러리
- Executors 인터페이스를 상속 받음
ExecutorService의 종류
- newCachedThreadPool
- 멀티 스레드 처리를 위한 스레드 풀을 생성하되 기존에 생성한 스레드를 가능한한 재사용
- 등록한 스레드를 모두 한번에 실행시키며 동시 처리에 대한 개수 제한이 없음
- 스레드를 캐싱하는 스레드 풀
(여기서 쓰이는 캐싱의 의미는 일정시간동안 스레드를 검사한다는 뜻
60초 동안 작업이 없으면 Pool에서 제거)
- newFixedThreadPool
- 입력 파라미터로 생성할 스레드 풀의 크기를 정의
- 스레드 풀의 크기를 넘으면 풀에 여유가 생길때까지 대기
- newSingleThreadExecutor
- 하나의 스레드로 처리하며 나머지 스레드 생성 요청은 현재 스레드가 종료될때까지 대기
- newWorkStealingPool
- 스레드 풀을 생성하며, 실행되는 하드웨어의 사용 가능한 모든 프로세스(CPU)의 코어를 쓰도록 병럴 처리 레벨을 설정
- 해당 하드웨어의 자원을 모두 선점하려고 하기 때문에 다른 프로세스 혹은 애플리케이션 성능에 영향을 끼침
- newScheduledThreadPool
- 일정 시간 뒤에 실행되는 작업이나 주기적으로 수행되는 작업을 수행
사용하기
ExecutorService 인스턴스를 생성해 준 후 submit으로 작업 전달
submit | 작업 전달 |
shutdownNow | 남아있는 스레드 강제 종료 |
shutdown | 작업 완료된 스레드 종료 |
awaitTermination | 지정된 시간 내에 종료되지 않으면 false를 리턴 |
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
실행문
});
executorService.shutdown();
// 20초 전에 완료되면 true
// 20초가 지나도 완료가 되지 않으면 false
executorService.awaitTermination(20, TimeUnit.SECONDS)
executorService.shutdownNow();
Thread.sleep(밀리초) 을 이용해 대기를 걸어둘 수 있음
ExecutorService를 만들어 작업을 실행하면, shutdown이 호출되기 전까지 계속해서 다음 작업을 대기하게 된다.
그러므로 작업이 완료되었다면 반드시 shutdown을 명시적으로 호출해주어야 한다.
💡 스케쥴러에 비동기 처리 적용하기
추가적으로 스케쥴러 전용 Config 파일을 별도로 설정해두면 기존 스케쥴러에 따로 작업할 필요 없이
자동으로 Config 파일이 적용된다.
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("scheduled-task-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
기존 스케쥴러에 따로 설정해줄 필요 없이 자동으로 적용된다.
만약 아래 코드처럼 synchronized를 붙여줄 경우 여러 스레드가 하나의 자원에 동시에 접근할 경우를 대비할 수 있다.
멀티스레드의 경우 스레드가 동시에 실행될 경우 서로 동기화되지 않아 데이터가 꼬일 수 있는 단점이 있다.
synchronized의 기능은 현재 데이터를 사용하고 있는 해당 스레드를 제외하고 나머지 스레드들은 데이터에 접근 할 수 없도록 막는 역할을 한다.
@Component
public class TestBatch {
@Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Seoul")
public synchronized void testScheduler() {
...
}
}
💡 TIPS!
1. mysql my.cnf 설정 방법
C:\Program Files\MySQL\MySQL Server 8.0\etc
my.cnf 파일 vim 편집기로 수정
2. Thread의 InterruptedException
Thread의 stop 메소드로 스레드를 종료하는 것은 스레드가 가진 모든 자원이 해제되므로 안전하지 않음 (interrupt를 이용하자)
인터럽트(Interrupt)
스레드를 종료하기 위한 메커니즘
InterruptedException
- 기존에 쓰레드가 실행 중이나, 비정상적인 실행 또는 종료를 수행하게 될 때 발생
참고사이트
'💡 백엔드 > Java' 카테고리의 다른 글
Java로 메일 가져오기 (0) | 2023.05.26 |
---|---|
Date 비교 메소드 (0) | 2023.05.26 |
Java로 메일 발송하기 (0) | 2023.05.26 |
yml 정보 클래스로 가져오기 (0) | 2023.05.26 |
SHA-256 해싱 알고리즘 (0) | 2023.05.26 |