非同期処理が多い Dart/Flutter では、「同時に複数処理が走ってデータが壊れる」といった問題が起こることがあります。
そんなとき便利なのが synchronized パッケージ。
これを使えば、簡単に 排他制御(mutex 的な仕組み) を導入できます。
インストール
pubspec.yaml
に追加します。
dependencies:
synchronized: ^3.0.0 # バージョンは最新を確認してください
基本的な使い方
synchronized
では Lock
クラスを使って排他制御を行います。
import 'package:flutter/material.dart';
import 'package:synchronized/synchronized.dart';
final _lock = Lock(); // 排他制御用のLock
int _counter = 0;
Future<void> incrementCounter() async {
await _lock.synchronized(() async {
// この中は同時に1つの処理しか入れない
final current = _counter;
await Future.delayed(const Duration(milliseconds: 500)); // わざと遅延
_counter = current + 1;
debugPrint("カウント: $_counter");
});
}
実際のUIサンプル
import 'package:flutter/material.dart';
import 'package:synchronized/synchronized.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("synchronized サンプル")),
body: const CounterExample(),
),
);
}
}
class CounterExample extends StatefulWidget {
const CounterExample({super.key});
@override
State<CounterExample> createState() => _CounterExampleState();
}
class _CounterExampleState extends State<CounterExample> {
final _lock = Lock();
int _counter = 0;
Future<void> _increment() async {
await _lock.synchronized(() async {
final current = _counter;
await Future.delayed(const Duration(milliseconds: 300));
setState(() {
_counter = current + 1;
});
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("カウント: $_counter", style: const TextStyle(fontSize: 24)),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 同時に複数押しても1つずつ順番に処理される
_increment();
},
child: const Text("カウントを増やす"),
)
],
),
);
}
}
ポイント
Lock
を生成してlock.synchronized(() { ... })
内に処理を記述await
を付けることで非同期処理も安全に直列化できる- データの競合や同時アクセスの不具合を防げる
まとめ
synchronized
は、
「複数の非同期処理が同じ変数を扱うときの安全装置」
としてとても便利です。
特にカウンターやファイルアクセス、DB操作などで 競合を防ぎたいとき に活用できます。