2026년 상식닷컴 선정 식당 & 카페 리스트
최근에 오픈한 호텔을 찾는다면 살펴보세요

SharedPreferences의 데이터를 다른 스레드에서 안전하게 사용하는 방법은 무엇인가요?

_____
Q: SharedPreferences의 데이터를 다른 스레드에서 안전하게 사용하는 방법은 무엇인가요?

A: SharedPreferences는 기본적으로 스레드에 안전(thread-safe)하게 설계되어 있어, 여러 스레드에서 동시에 읽기 및 쓰기 작업을 수행해도 데이터 손상 위험이 적습니다. 그러나 안전하게 사용하기 위해 다음 사항들을 고려해야 합니다.

1. 읽기 작업(Read)
- 별도의 동기화 없이도 여러 스레드에서 동시에 SharedPreferences의 `get` 메서드들을 호출하는 것은 안전합니다.
- 읽기 작업은 가볍고 빠르므로 UI 스레드 또는 백그라운드 스레드에서 자유롭게 사용할 수 있습니다.

2. 쓰기 작업(Write)
- SharedPreferences.Editor의 `apply()`와 `commit()`은 내부적으로 동기화되어 있어, 여러 스레드에서 동시에 호출해도 대체로 안전합니다.
- 하지만, `commit()`은 동기 방식으로 메인 스레드를 차단할 수 있으므로, 백그라운드 스레드에서 호출하는 것이 좋습니다.
- `apply()`는 비동기 방식으로 동작하며 내부적으로 atomic commit을 보장하므로 주로 권장됩니다.

3. 동시 쓰기 충돌 방지
- 여러 스레드가 동시에 수정 작업을 할 때, 마지막으로 호출된 쓰기 작업이 기존 데이터를 덮어쓸 수 있습니다.
- 중요하거나 복잡한 트랜잭션이 필요한 경우, 별도의 동기화 메커니즘(예: `synchronized` 블록, `ReentrantLock`)을 사용해 쓰기 작업을 직렬화하는 것이 안전합니다.
- 또는, 데이터를 한번에 모두 변경하지 않고 부분적으로 수정하는 경우, 값을 읽고 변환 후 저장하는 사이에 다른 스레드가 변경할 수 있음을 염두에 둡니다.

4. LiveData 혹은 Flow 등 비동기 데이터 스트림 활용
- 여러 스레드에서 실시간으로 데이터 변화를 감지하고 싶다면 SharedPreferences에 직접 접근하기보다, LiveData, Kotlin Flow, RxJava 등과 연동하여 구독하도록 하는 방법이 있습니다.

5. 요약
- 읽기는 별도 동기화 없이 안전
- 쓰기는 `apply()`를 이용해 비동기 커밋 권장
- 동시 다중 쓰기 상황에서는 별도 동기화 고려
- UI 스레드 차단 방지를 위해 `commit()` 호출은 피함

따라서, 일반적인 경우에는 SharedPreferences를 여러 스레드에서 편리하게 사용할 수 있으나, 데이터 정합성이 매우 중요한 경우에는 추가적인 동기화 메커니즘을 활용하는 것이 바람직합니다.
SharedPreferences는 Android에서 간단한 데이터를 저장하고 불러오는 데 사용되는 API입니다.

그러나 SharedPreferences는 기본적으로 스레드 안전(thread-safe)하지 않기 때문에, 여러 스레드에서 동시에 접근할 경우 데이터 손상이나 예기치 않은 동작이 발생할 수 있습니다.

따라서 SharedPreferences의 데이터를 다른 스레드에서 안전하게 사용하기 위해서는 몇 가지 방법을 고려해야 합니다.

1. Synchronization 사용하기 가장 간단한 방법은 Java의 `synchronized` 키워드를 사용하는 것입니다.

이를 통해 특정 코드 블록에 대한 접근을 한 번에 하나의 스레드만 가능하도록 제한할 수 있습니다.

```java public class SharedPreferencesManager { private SharedPreferences sharedPreferences; public SharedPreferencesManager(Context context) { sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); } public synchronized void saveData(String key, String value) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(key, value); editor.apply(); // apply()는 비동기적으로 저장 } public synchronized String getData(String key) { return sharedPreferences.getString(key, null); } } ``` 이 방법은 간단하지만, 성능에 영향을 줄 수 있습니다.

특히, 많은 스레드가 동시에 접근할 경우 병목 현상이 발생할 수 있습니다.



2. ReadWriteLock 사용하기 Java의 `ReadWriteLock`을 사용하여 읽기와 쓰기 작업을 분리할 수 있습니다.

읽기 작업은 여러 스레드가 동시에 수행할 수 있지만, 쓰기 작업은 단독으로 수행해야 합니다.

```java import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class SharedPreferencesManager { private SharedPreferences sharedPreferences; private ReadWriteLock lock = new ReentrantReadWriteLock(); public SharedPreferencesManager(Context context) { sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); } public void saveData(String key, String value) { lock.writeLock().lock(); try { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(key, value); editor.apply(); } finally { lock.writeLock().unlock(); } } public String getData(String key) { lock.readLock().lock(); try { return sharedPreferences.getString(key, null); } finally { lock.readLock().unlock(); } } } ``` 이 방법은 읽기 작업이 많고 쓰기 작업이 적은 경우에 성능을 개선할 수 있습니다.



3. Handler 사용하기 Android의 `Handler`를 사용하여 UI 스레드에서 SharedPreferences에 접근하도록 할 수 있습니다.

이 방법은 UI 스레드에서만 SharedPreferences에 접근하도록 보장합니다.

```java public class SharedPreferencesManager { private SharedPreferences sharedPreferences; private Handler handler = new Handler(Looper.getMainLooper()); public SharedPreferencesManager(Context context) { sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); } public void saveData(final String key, final String value) { handler.post(new Runnable() { @Override public void run() { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(key, value); editor.apply(); } }); } public void getData(final String key, final DataCallback callback) { handler.post(new Runnable() { @Override public void run() { String value = sharedPreferences.getString(key, null); callback.onDataRetrieved(value); } }); } public interface DataCallback { void onDataRetrieved(String value); } } ``` 이 방법은 UI 스레드에서만 SharedPreferences에 접근하므로 스레드 안전성을 보장합니다.



4. Room 데이터베이스 사용하기 SharedPreferences는 간단한 데이터 저장에 적합하지만, 복잡한 데이터 구조나 대량의 데이터를 다루는 경우 Room 데이터베이스를 사용하는 것이 좋습니다.

Room은 SQLite 데이터베이스를 추상화하여 스레드 안전성을 제공하며, 비동기 작업을 쉽게 처리할 수 있습니다.

결론 SharedPreferences를 다른 스레드에서 안전하게 사용하기 위해서는 여러 가지 방법이 있습니다.

각 방법은 특정 상황에 따라 장단점이 있으므로, 애플리케이션의 요구 사항에 맞는 방법을 선택하는 것이 중요합니다.

간단한 데이터 저장에는 `synchronized`나 `ReadWriteLock`을 사용할 수 있으며, UI 스레드에서의 접근이 필요할 경우 `Handler`를 사용할 수 있습니다.

복잡한 데이터 구조나 대량의 데이터를 다루는 경우 Room 데이터베이스를 고려하는 것이 좋습니다.

작성자: 이은채 [비회원] | 작성일자: 1년 전 2024-11-24 06:31:52
조회수: 195 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.