Category: CS

0

[JAVA] - Cold Start

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 🧊 Cold Start란?Cold Start는 JVM이 애플리케이션이 처음 실행될 때 초기화 과정 때문에 발생하는 지연(latency) 을 의미합니다. 마치 추운 겨울날 자동차 시동을 걸 때 엔진이 따뜻해질 때까지 시간이 걸리는 것과 비슷합니다. 일반적인 서버 환경에서는 애플리케이션이 한 번 시작되면 계속 실행되기 때문에 이 문제가 크게 부각되지 않았습니다. 하지만 MSA 는 인스턴스가 빈번히 생성 및 소멸되고 여러 서버가 긴밀히 통신하는 환경입니다. 이로 인해 특정 시스템이 재부팅되면 연결된 다른 시스템의 응답 속도까지 지연되는 문제가 발생했으며, 무중단 배포·잦은 배포·오토스케일링 등으로 인해 기존 아키텍처보다 성능 지연 현상이 더 빈번하게 나타나게 되었고, 전체적인 서비스 성능 이슈의 문제가 됐습니다. 🚦 Cold Start가 발생하는 이유Java 애플리케이션은 네이티브 코드가 아닌 JVM 위에서 바이트코드 실행 방식으로 동작하기 때문에, 첫 실행 시 다음과 같은 과정에서 오버헤드가 발생합니다. 1. JVM 초기화 과정의 복잡성Java 애플리케이션이 시작될 때 여러 단계의 초기화 과정을 거쳐야 합니다:

0

[Java] - 가비지 컬렉션 히스토리

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 초기 GC들 (JDK 1.0~1.4)Serial GC 가장 오래된 GC 단일 스레드로 동작 작은 애플리케이션이나 클라이언트 환경에 적합 Stop-the-World 시간이 길어서 현재는 제한적으로 사용 Parallel GC (Throughput Collector) JDK 1.4에서 도입 멀티코어 환경에서 여러 스레드를 사용해 처리량을 개선 JDK 6~8에서 기본 GC 여전히 긴 정지 시간이 단점 저지연 목표 GC들 (JDK 1.4~)Concurrent Mark Sweep (CMS) GC

0

[Javascript] Axios 파일 업로드 및 다운로드

파일 업로드 및 다운로드📁 파일 업로드// 단일 파일 업로드async function uploadFile(file, onProgress) { const formData = new FormData(); formData.append('file', file); formData.append('category', 'documents'); formData.append('description', [file.name](http://file.name)); try { const response = await [axios.post](http://axios.post)('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (progressEvent) => { const percentCompleted = Math.round( (progressEvent.loaded * 100) / [progressEvent.total](http://progressEvent.total) ); console.log(`업로드 진행률: ${percentCompleted}%`); onProgress?.(percentCompleted); } }); return [response.data](http://response.data); } catch (error) { console.error('파일 업로드 실패:', error); throw error; }}// 다중 파일 업로드async function uploadMultipleFiles(files) { const formData = new FormData(); files.forEach((file, index) => { formData.append(`files`, file); }); const response = await [axios.post](http://axios.post)('/api/upload/multiple', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); return [response.data](http://response.data);}// 사용 예시const fileInput = document.getElementById('fileInput');fileInput.addEventListener('change', async (event) => { const file = [event.target](http://event.target).files[0]; if (file) { try { const result = await uploadFile(file, (progress) => { console.log(`업로드 진행률: ${progress}%`); }); console.log('업로드 완료:', result); } catch (error) { console.error('업로드 에러:', error); } }}); 📥 파일 다운로드// 파일 다운로드async function downloadFile(fileId, filename) { try { const response = await axios.get(`/api/files/${fileId}/download`, { responseType: 'blob' }); // Blob을 사용하여 파일 다운로드 트리거 const url = window.URL.createObjectURL(new Blob([[response.data](http://response.data)])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', filename); document.body.appendChild(link); [link.click](http://link.click)(); document.body.removeChild(link); // 메모리 정리 window.URL.revokeObjectURL(url); } catch (error) { console.error('파일 다운로드 실패:', error); }} 에러 처리 베스트 프랙티스🛡️ 포괄적인 에러 처리// 에러 타입별 처리 함수function handleApiError(error) { if (error.response) { // 서버가 응답했지만 상태 코드가 2xx 범위를 벗어남 const { status, data } = error.response; switch (status) { case 400: console.error('잘못된 요청:', data.message); break; case 401: console.error('인증 실패 - 로그인이 필요합니다'); // 로그인 페이지로 리다이렉트 window.location.href = '/login'; break; case 403: console.error('접근 권한이 없습니다'); break; case 404: console.error('요청한 리소스를 찾을 수 없습니다'); break; case 429: console.error('요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요'); break; case 500: console.error('서버 내부 오류가 발생했습니다'); break; default: console.error(`서버 오류 (${status}):`, data.message); } return { type: 'response', status, message: data.message }; } else if (error.request) { // 요청은 전송되었지만 응답을 받지 못함 (네트워크 오류) console.error('네트워크 오류: 서버에 연결할 수 없습니다'); return { type: 'network', message: '네트워크 연결을 확인해주세요' }; } else { // 요청 설정 중에 오류 발생 console.error('요청 설정 오류:', error.message); return { type: 'config', message: error.message }; }}// 재시도 로직이 포함된 API 호출async function apiCallWithRetry(requestFn, maxRetries = 3, delay = 1000) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await requestFn(); } catch (error) { const errorInfo = handleApiError(error); if (attempt === maxRetries || errorInfo.type === 'response') { throw error; // 최대 재시도 횟수 도달 또는 서버 응답 오류 } console.log(`재시도 ${attempt}/${maxRetries} - ${delay}ms 후 다시 시도...`); await new Promise(resolve => setTimeout(resolve, delay * attempt)); } }}// 사용 예시async function fetchUserData(userId) { return apiCallWithRetry( () => axios.get(`/api/users/${userId}`), 3, // 최대 3번 재시도 1000 // 1초 간격 );}

0

[Javascript] Axios 인터셉터

인터셉터로 요청/응답 제어하기📤 요청 인터셉터// 모든 요청에 공통 로직 적용axios.interceptors.request.use( (config) => { // 요청 시작 로그 console.log(`🚀 API 요청: ${config.method?.toUpperCase()} ${config.url}`); // 인증 토큰 자동 추가 const token = localStorage.getItem('accessToken'); if (token) { config.headers.Authorization = `Bearer ${token}`; } // 요청 시간 기록 (성능 측정용) config.metadata = { startTime: new Date() }; return config; }, (error) => { console.error('❌ 요청 설정 오류:', error); return Promise.reject(error); }); 📥 응답 인터셉터// 모든 응답에 공통 로직 적용axios.interceptors.response.use( (response) => { // 응답 시간 계산 const endTime = new Date(); const duration = endTime - response.config.metadata.startTime; console.log(`✅ API 응답: ${response.config.url} (${duration}ms)`); return response; }, async (error) => { const originalRequest = error.config; // 401 에러: 토큰 갱신 처리 if (error.response?.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const refreshToken = localStorage.getItem('refreshToken'); const response = await [axios.post](http://axios.post)('/auth/refresh', { refreshToken }); const newToken = [response.data](http://response.data).accessToken; localStorage.setItem('accessToken', newToken); // 원래 요청에 새 토큰 적용 후 재시도 originalRequest.headers.Authorization = `Bearer ${newToken}`; return axios(originalRequest); } catch (refreshError) { // 토큰 갱신 실패 시 로그인 페이지로 리다이렉트 localStorage.clear(); window.location.href = '/login'; } } // 에러 로깅 console.error('❌ API 에러:', { url: error.config?.url, status: error.response?.status, message: error.message }); return Promise.reject(error); }); 실전 예제: API 클래스 구현🏢 사용자 관리 API 클래스class UserService { constructor() { this.client = axios.create({ baseURL: process.env.REACT_APP_API_URL || 'https://api.example.com', timeout: 10000 }); this.setupInterceptors(); } setupInterceptors() { // 요청 인터셉터: 인증 토큰 자동 추가 this.client.interceptors.request.use(config => { const token = this.getAuthToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 응답 인터셉터: 에러 처리 this.client.interceptors.response.use( response => response, error => this.handleError(error) ); } getAuthToken() { return localStorage.getItem('authToken'); } handleError(error) { const message = error.response?.data?.message || error.message; throw new Error(`API 요청 실패: ${message}`); } // 사용자 목록 조회 async getUsers(options = {}) { const { page = 1, limit = 10, search = '' } = options; const response = await this.client.get('/users', { params: { page, limit, search } }); return { users: [response.data.data](http://response.data.data), totalCount: [response.data.total](http://response.data.total), currentPage: page }; } // 사용자 상세 조회 async getUserById(userId) { const response = await this.client.get(`/users/${userId}`); return [response.data](http://response.data); } // 사용자 생성 async createUser(userData) { const response = await [this.client.post](http://this.client.post)('/users', userData); return [response.data](http://response.data); } // 사용자 정보 수정 async updateUser(userId, userData) { const response = await this.client.put(`/users/${userId}`, userData); return [response.data](http://response.data); } // 사용자 삭제 async deleteUser(userId) { await this.client.delete(`/users/${userId}`); return { success: true, userId }; } // 사용자 검색 async searchUsers(query) { const response = await this.client.get('/users/search', { params: { q: query } }); return [response.data](http://response.data); }}// 싱글톤 패턴으로 사용export const userService = new UserService();// 사용 예시async function handleUserOperations() { try { // 사용자 목록 조회 const userList = await userService.getUsers({ page: 1, limit: 20, search: 'john' }); console.log('사용자 목록:', userList); // 새 사용자 생성 const newUser = await userService.createUser({ name: '김개발', email: '[kim.dev@example.com](mailto:kim.dev@example.com)', role: 'developer' }); console.log('생성된 사용자:', newUser); // 사용자 정보 수정 const updatedUser = await userService.updateUser([newUser.id](http://newUser.id), { name: '김시니어', role: 'senior-developer' }); console.log('수정된 사용자:', updatedUser); } catch (error) { console.error('사용자 작업 중 오류:', error.message); }}

0

[Javascript] Axios 사용하기 (고급편)

고급 설정 및 인스턴스⚙️ 상세한 요청 설정const requestConfig = { method: 'get', url: '/api/users', baseURL: 'https://api.example.com', // 헤더 설정 headers: { 'Authorization': 'Bearer token123', 'Content-Type': 'application/json', 'Accept': 'application/json' }, // URL 파라미터 params: { page: 1, size: 20 }, // 타임아웃 (밀리초) timeout: 10000, // 응답 타입 responseType: 'json', // 'json', 'text', 'blob', 'stream' 등 // 요청 바디 (POST, PUT, PATCH) data: { name: '홍길동', email: '[hong@example.com](mailto:hong@example.com)' }};const response = await axios(requestConfig); 🏗️ Axios 인스턴스 생성// API별 인스턴스 생성const apiClient = axios.create({ baseURL: 'https://api.myservice.com/v1', timeout: 15000, headers: { 'Content-Type': 'application/json' }});// 인증이 필요한 API용 인스턴스const authApiClient = axios.create({ baseURL: 'https://api.myservice.com/v1', timeout: 10000, headers: { 'Authorization': `Bearer ${getAuthToken()}` }});// 인스턴스 사용const users = await apiClient.get('/users');const profile = await authApiClient.get('/profile'); 인터셉터로 요청/응답 제어하기웹 개발을 하다 보면 서버와 통신할 때 반복적으로 처리해야 하는 공통 로직들이 생깁니다.예를 들어 JWT 토큰을 모든 요청 헤더에 붙인다거나, 에러 응답을 일관되게 처리한다거나, 응답 데이터 구조를 통일한다거나 하는 일들이죠. 이때 유용하게 사용할 수 있는 기능이 바로 Axios Interceptor입니다. 📤 요청 인터셉터

0

[Javascript] Axios 사용하기

웹 개발에서 API 통신은 필수불가결한 요소입니다. 그 중에서도 Axios는 가장 인기 있고 강력한 JavaScript HTTP 클라이언트 라이브러리로 자리잡고 있습니다. 이 글에서는 Axios의 기본 사용법부터 고급 기능까지 실무에서 바로 활용할 수 있는 예제와 함께 상세히 알아보겠습니다. Axios란 무엇인가?Axios는 Promise 기반의 HTTP 클라이언트 라이브러리로, 브라우저와 Node.js 환경에서 모두 사용할 수 있습니다. ✨ 주요 특징 Promise 기반: async/await와 완벽 호환 요청/응답 인터셉터: 공통 로직 처리 가능 자동 JSON 변환: 별도 변환 과정 불필요 요청/응답 변환: 데이터를 원하는 형태로 가공 요청 취소: 불필요한 요청 중단 가능 광범위한 브라우저 지원: IE11까지 지원 설치 및 기본 설정📦 설치# npm 사용시npm install axios# yarn 사용시 yarn add axios# pnpm 사용시pnpm add axios

0

네트워크 트래픽의 3가지 패턴 - Ingress, Egress, East-West Traffic

현대 IT 인프라를 이해하려면 데이터가 어떻게 흐르는지 파악하는 것이 필수입니다. 특히 클라우드 환경과 마이크로서비스 아키텍처가 보편화되고 트래픽의 움직임이 클라우드 서비스의 과금 요소중에 하나가 됨으로써 네트워크 트래픽 패턴을 정확히 이해하는 것은 더욱 중요해졌습니다. 오늘은 인프라를 운영하면서 알아두면 좋을 3가지 트래픽 패턴에 대해 알아보겠습니다. 📌 1. Ingress: 외부에서 내부로 들어오는 트래픽 Ingress는 클러스터 외부 → 내부로 들어오는 요청입니다. Ingress Traffic은 외부에서 우리 네트워크나 시스템으로 들어오는 모든 트래픽을 의미합니다. 대표적인 예시는 인터넷 사용자가 웹 애플리케이션에 접속하는 경우입니다. 실무 예시🌐 사용자 브라우저 → 웹 서버 (HTTP/HTTPS 요청)📱 모바일 앱 → API 게이트웨이 (REST API 호출)🔗 외부 시스템 → 내부 서비스 (Webhook, 데이터 동기화) 📌 2. Egress: 내부에서 외부로 나가는 트래픽 Egress는 클러스터 내부 → 외부로 나가는 요청 Egress Traffic은 우리 시스템에서 외부로 나가는 모든 트래픽입니다. 예를 들어 응답 데이터, 외부 API 호출, 백업 데이터 전송등을 할때 발생합니다.

0

[데이터 베이스] Cursor 란?

목차 [데이터 베이스] 자바에서 대용량 조회 시 애플리케이션과 데이터베이스는 어떻게 동작하는가? [데이터 베이스] Cursor 란? 🔎 Cursor 란?커서는 쿼리 결과셋을 탐색할 수 있는 포인터 입니다. DB 는 쿼리 결과 데이터를 반환할 때, 커서(cursor) 를 생성하여 현재 어디까지 데이터가 반환됐는지, 어디부터 읽으면 될지를 알 수 있습니다. 주로 프로그램 내에서 루프를 돌며 한 줄씩 데이터를 처리할 필요가 있을 때 사용합니다. ✅ Cursor 사용법1. DECLARE - Cursor 선언 및 생성커서를 사용하고 싶은 쿼리가 있으면 아래 SQL 을 이용해 커서를 정의 및 생성해줍니다.

0

[데이터 베이스] 자바에서 대용량 조회 시 애플리케이션과 데이터베이스는 어떻게 동작하는가?

목차 [데이터 베이스] 자바에서 대용량 조회 시 애플리케이션과 데이터베이스는 어떻게 동작하는가? [데이터 베이스] Cursor 란? 🤔 대용량 조회 시 애플리케이션과 데이터베이스는 어떻게 동작하는가?대용량 데이터를 조회해야 하는 상황이 생기면, 우리는 종종 “애플리케이션 메모리는 괜찮을까?”, “DB에 부하가 가지는 않을까?” 같은 고민을 하게 됩니다. 자바 JDBC 에서는 이런 상황을 제어하기 위해 cursor 와 fetch size 를 이용합니다. 🕵️‍♂️ 대용량 조회의 기본 흐름JDBC로 쿼리를 실행할 때, 결과가 수천~수만 건이라면 어떻게 처리될까요? 예를 들어, 아래 코드를 실행했다고 가정해 봅시다. PreparedStatement ps = conn.prepareStatement("SELECT * FROM large_table");ps.setFetchSize(100); // 한 번에 100건씩 가져오도록 설정ResultSet rs = ps.executeQuery(); 이 코드가 실행될 때 내부적으로 일어나는 동작은 아래와 같습니다 애플리케이션이 DB에 쿼리를 날립니다. DB는 전체 결과를 준비하고 커서를 생성합니다. JDBC 드라이버는 커서로부터 100 건씩 row 를 가져옴니다 row 를 다 소비하면 JDBC는 다음 100 건을 요청합니다. 이 과정을 반복하여 전체 데이터를 처리합니다.

0

쓰레드와 메모리구조

목차 Thread Safe 쓰레드와 메모리구조 쓰레드 프로세스 동기화 프로세스 스케줄링 알고리즘 프로세스 상태와 스케줄러 Inter Process Communication(프로세스간의 통신) 프로세스 메모리 영역 Process (프로세스) 참고 https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4 쓰레드 메모리 구조프로세스 안에서 생성되는 쓰레드는 프로세스의 메모리 영역을 사용하게 됩니다. 프로세스내 메모리 영역 중 Code, Data, Heap 영역은 모든 쓰레드가 공유해서 사용하고 각 쓰레드 별로 Stack 영역이 생성됩니다. 프로세스 메모리 구조

0

Service Discovery 패턴

참고 https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/ https://velog.io/@hoonki/마이크로서비스-패턴-서비스-디스커버리 🕵️‍♂️ Service Discovery 패턴이 등장하게 된 배경기존 서비스 인스턴스의 개수와 IP 가 고정적이였던 온 프레미스 환경과 달리 MSA 환경에서는 Application 들이 AutoScaling 을 하면서 동적으로 줄었다가 늘어나면서 IP 자체도 고정이 아닌 동적으로 바뀌게 됐습니다. Client 나 Gateway 입장에서 서비스 인스턴스들이 동적으로 늘었는지 줄었는지에 대한 파악을 하기가 어려운 문제가 있었고 그에 따른 LoadBalancing 하는데 어려움이 있었습니다. 변경 및 추가된 서비스들의 위치와 주소를 쉽게 파악하기 위해 Service Discovery 가 등장하게 됐습니다. 출처: https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/ ✅ 서비스 등록 - Service RegistryService Discovery 패턴에서는 Service EndPoint 를 조회 및 관리하기 위한 저장소가 필요한데, 이를 Service Registry 라 합니다. MSA 에서 각 서비스들이 실행하게 되면 Service Registry 에 자신의 EndPoint 들을 등록합니다. 그리고 주기적으로 Service Registry 에 등록된 서비스 중이 정상적인지 Health Check 를 진행하고, 정상적인 응답이 안올 경우 목록에서 삭제하는 방식으로 진행합니다.

0

데이터 베이스 - Soft Delete & Hard Delete

Hard DeleteHard Delete 는 데이터베이스에서 특정 레코드를 완전히 삭제하는 것을 의미합니다. 이 경우 해당 레코드는 영구적으로 삭제되어 복구할 수 없습니다. Soft DeleteSoft Delete 는 데이터베이스에서 특정 레코드를 논리적으로 삭제하지만, 물리적으로는 데이터베이스에 그대로 남아있는 것을 의미합니다. 즉, 해당 레코드를 삭제했을 때, 실제로는 데이터베이스에서 해당 레코드를 삭제하지 않고, 삭제되었다는 표시를 하여 삭제된 것처럼 처리합니다. 이렇게 하면 데이터를 복구할 수 있으며, 사용자가 실수로 데이터를 삭제했을 때 복구할 수 있는 장점이 있습니다. 소프트 삭제를 구현하는 방법에는 다양한 방법이 있습니다. 가장 일반적인 방법은 레코드에 삭제 플래그 (delete flag)라는 특별한 필드를 추가하고, 이 필드에 삭제 여부를 표시하는 것입니다. 이렇게 하면 삭제된 레코드를 쉽게 찾을 수 있고, 삭제된 레코드를 복구할 수도 있습니다.

0

[JAVA] - 가비지 컬렉션 튜닝

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 참고 https://d2.naver.com/helloworld/37111 가비지 컬렉션 튜닝 전체적으로 GC(Minor GC + Major GC) 가 적게 발생하기 위해서는 우선적으로 객체를 적게 생성하면 된다. Old Generation 으로 넘어가는 객체의 수 최소화 (횟수) Full GC 시간 줄이기 (영역) 1. Old Generation 으로 넘어가는 객체의 수 최소화New Generation 의 경우 Old Generation 영역보다 작기 때문에 상대적으로 Stop The World 가 작게 발생한다.

0

데이터 베이스 - Index

Index 란?인덱스는 데이터베이스에서 테이블의 검색 속도를 높이기 위한 자료 구조 입니다. 인덱스는 테이블의 컬럼을 기반으로 만들어지며, 이를 사용하여 특정 데이터를 빠르게 찾을 수 있습니다. 일반적으로 인덱스는 B-트리나 해시 테이블과 같은 자료 구조를 사용하여 구현됩니다. B-트리 인덱스는 매우 일반적인 인덱스 유형으로, 테이블의 키 값이 정렬된 트리 구조를 사용하여 저장됩니다. 이 구조는 검색, 삽입 및 삭제 작업에 대해 매우 효율적입니다. 해시 인덱스는 테이블의 키 값을 해시 함수를 사용하여 저장하며, 빠른 검색 속도를 제공하지만 범위 검색이나 정렬 기능이 없습니다. 인덱스를 사용하면 특정 행을 검색하는 데 걸리는 시간이 줄어듭니다. 특히 대량의 데이터가 있는 경우 검색 성능을 향상시키는 데 매우 유용합니다. 그러나 인덱스는 테이블의 크기와 관련하여 저장 공간을 차지하므로 인덱스를 너무 많이 사용하면 데이터베이스 성능이 떨어질 수 있습니다. 또한 인덱스를 사용하면 데이터를 삽입, 수정 또는 삭제할 때 추가 작업이 필요하므로 데이터베이스 성능에 영향을 미칠 수 있습니다. 따라서 인덱스는 데이터베이스의 검색 성능을 향상시키는 데 매우 유용하지만, 사용에 주의해야 합니다. 적절한 인덱스를 사용하면 데이터베이스의 성능을 최적화할 수 있습니다. Index Scan 종류 Table Full Scan : 테이블 전체 탐색 Index Unique Scan : 인덱스 수직 탐색 Index Full Sacn : 인덱스 전체 탐색 Index Range Scan : 인덱스 범위 탐색 Index Skip Scan : 인덱스 스킵 탐색 Table Full Scan - 테이블 전체 스캔 전체 테이블의 모든 레코드를 검색하는 방식

0

Thread Safe

목차 Thread Safe 쓰레드와 메모리구조 쓰레드 프로세스 동기화 프로세스 스케줄링 알고리즘 프로세스 상태와 스케줄러 Inter Process Communication(프로세스간의 통신) 프로세스 메모리 영역 Process (프로세스) Thread Safe 란?Thread 는 프로세스와 다르게 프로세스 내부에서 할당 받은 자원을 공유 한다. 멀티 쓰레드 환경에서 한번에 공유 자원에 접근하는 Race Condition 이 발생해도 올바른 실행 결과가 나오게 보장함을 의미한다. Thread Safe 를 지키는 방법 Re-entrancy 어떤 함수가 한 스레드에 의해 호출되어 실행 중일 때, 다른 스레드가 그 함수를 호출하더라도 그 결과가 각각에게 올바로 주어져야 한다. Thread Local Storage 공유 자원의 사용을 최대한 줄여 각각의 스레드에서만 접근 가능한 저장소들을 사용함으로써 동시 접근을 막는다. 이 방식은 동기화 방법과 관련되어 있고, 또한 공유상태를 피할 수 없을 때 사용하는 방식이다. Mutual Exclusion Thread에 Lock, Semaphore, Mutex 를 걸어서 공유자원에는 하나의 thread만 접근 가능하게 한다. Atomic operations 데이터 변경시 atomic하게 데이터에 접근하도록 만듭니다. Immutable Object 자바의 Final 처럼 객체를 생성한 후 수정이 불가능 하게 한다. Thread 동기화 실행 순서 에 따른 동기화 메모리 접근 에 대한 동기화 실행 순서에 따른 동기화 쓰레드의 실행 순서를 정하고 정해진 순서에 따라 작업을 처리하도록 한다.