涉及到多线程时,必须要考虑锁,数据同步。
找到资料:synchronized: https://pub.dev/packages/synchronized#-readme-tab-
最基本的一个应用:
有一个变量a, 当多个线程访问时,必须保证同一时刻只有一个线程在读取/设置(类似于 C# 中的 lock(){} )。我们可以使用 synchronized 来处理就非常容易了。如:
_lock.synchronized(()async{
//dealing with var a
//...
});
这里有一个需要注意的地方是,这个同步程序块(程序函数)是异步的,举例下
先生成一个默认的工程,然后添加一个函数,函数的内容如下:
debugPrint("${DateTime.now().toString()}$_bCounting");
_lock.synchronized( ()async{//block 1
_bCounting = !_bCounting;
debugPrint("1:in lock. changed to: $_bCounting");
_lock.synchronized( ()async{//block 2
_bCounting = !_bCounting;
debugPrint("2:in lock. changed to: $_bCounting");
});
});
添加2个变量
bool _bCounting = false;
var _lock = Lock();
可以添加一个按钮,然后点击调用上面的函数,结果如下:(按钮点击了2次)
2019-12-05 15:15:38.958 false
1:in lock. changed to: true
2:in lock. changed to: false
2019-12-05 15:15:45.535 false
1:in lock. changed to: true
2:in lock. changed to: false
似乎lock没有起作用。调用了2次,都进入了程序块。
实际问题出在: 2个程序块都没有等待完成,所以实际的情况是 block1 先完成,解锁,再顺利进入 block2
改一下程序,如下:block2 中加了 await
debugPrint("${DateTime.now().toString()}$_bCounting");
_lock.synchronized( ()async{
_bCounting = !_bCounting;
debugPrint("1:in lock. changed to: $_bCounting");
await _lock.synchronized( ()async{ //added keyword "await"
_bCounting = !_bCounting;
debugPrint("2:in lock. changed to: $_bCounting");
});
});
运行结果如下:(按钮点击了2次)
2019-12-05 15:23:22.241 false
1:in lock. changed to: true
2019-12-05 15:23:24.196 true
现在每一次运行时,需要等待block2结束,而 block2 需要的资源需要等block1先结束,互相等待变成了死锁。
--END--