Dart/Flutterで排他制御を簡単にする「synchronized」の使い方

非同期処理が多い 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操作などで 競合を防ぎたいとき に活用できます。

詳細: pub.dev/packages/synchronized

タイトルとURLをコピーしました