Thread.setInterval(callback, delay[, ...args])
参见
timers.setInterval()
open in new window
。
区别在于, 该定时器会在该线程执行。如果当前线程仍未开始执行或已经执行结束,则抛出
IllegalStateException
。
参见
timers.setImmediate()
open in new window
。
区别在于, 该定时器会在该线程执行。如果当前线程仍未开始执行或已经执行结束,则抛出
IllegalStateException
。
Thread.clearInterval(id)
参见
timers.clearInterval()
open in new window
。
区别在于, 该定时器会在该线程执行。如果当前线程仍未开始执行或已经执行结束,则抛出
IllegalStateException
。
Thread.clearTimeout(id)
参见
timers.clearTimeout()
open in new window
。
区别在于, 该定时器会在该线程执行。如果当前线程仍未开始执行或已经执行结束,则抛出
IllegalStateException
。
参见
timers.clearImmediate()
open in new window
。
区别在于, 该定时器会在该线程执行。如果当前线程仍未开始执行或已经执行结束,则抛出
IllegalStateException
。
线程安全
线程安全问题是一个相对专业的编程问题,本章节只提供给有需要的用户。
引用维基百科的解释:
线程安全是编程中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。
在Auto.js中,线程间变量在符合JavaScript变量作用域规则的前提下是共享的,例如全局变量在所有线程都能访问,并且保证他们在所有线程的可见性。但是,不保证任何操作的原子性。例如经典的自增"i++"将不是原子性操作。
Rhino和Auto.js提供了一些简单的设施来解决简单的线程安全问题,如锁
threads.lock()
, 函数同步锁
sync()
, 整数原子变量
threads.atomic()
等。
例如,对于多线程共享下的整数的自增操作(自增操作会导致问题,是因为自增操作实际上为
i = i + 1
,也就是先读取i的值, 把他加1, 再赋值给i, 如果两个线程同时进行自增操作,可能出现i的值只增加了1的情况),应该使用
threads.atomic()
函数来新建一个整数原子变量,或者使用锁
threads.lock()
来保证操作的原子性,或者用
sync()
来增加同步锁。
线程不安全的代码如下:
var i = 0;
threads.start(function(){
while(true){
log(i++);
});
while(true){
log(i++);
此段代码运行后打开日志,可以看到日志中有重复的值出现。
使用
threads.atomic()
的线程安全的代码如下:
var i = threads.atomic();
threads.start(function(){
while(true){
log(i.getAndIncrement());
});
while(true){
log(i.getAndIncrement());
或者:
var lock = threads.lock();
var i = 0;
threads.start(function(){
while(true){
lock.lock();
log(i++);
lock.unlock();
});
while(true){
lock.lock();
log(i++);
lock.unlock();
或者:
var i = 0;
var getAndIncrement = sync(function(){
return i++;
});
threads.start(function(){
while(true){
log(getAndIncrement());
});
while(true){
log(getAndIncrement());
另外,数组Array不是线程安全的,如果有这种复杂的需求,请用Android和Java相关API来实现。例如
CopyOnWriteList
,
Vector
等都是代替数组的线程安全的类,用于不同的场景。例如:
var nums = new java.util.Vector();
nums.add(123);
nums.add(456);
toast("长度为" + nums.size());
toast("第一个元素为" + nums.get(0));
但很明显的是,这些类不像数组那样简便易用,也不能使用诸如
slice()
之类的方便的函数。在未来可能会加入线程安全的数组来解决这个问题。当然您也可以为每个数组的操作加锁来解决线程安全问题:
var nums = [];
var numsLock = threads.lock();
threads.start(function(){
numsLock.lock();
nums.push(123);
log("线程: %s, 数组: %s", threads.currentThread(), nums);
numsLock.
unlock();
});
threads.start(function(){
numsLock.lock();
nums.push(456);
log("线程: %s, 数组: %s", threads.currentThread(), nums);
numsLock.unlock();
});
numsLock.lock();
nums.pop();
log("线程: %s, 数组: %s", threads.currentThread(), nums);
numsLock.unlock();
sync(func)
-
func
{Function} 函数
-
返回 {Function}
给函数func加上同步锁并作为一个新函数返回。
var i = 0;
function add(x){
i += x;
var syncAdd = sync(add);
syncAdd(10);
toast(i);
线程通信
Auto.js提供了一些简单的设施来支持简单的线程通信。
threads.disposable()
用于一个线程等待另一个线程的(一次性)结果,同时
Lock.newCondition()
提供了Condition对象用于一般的线程通信(await, signal)。另外,
events
模块也可以用于线程通信,通过指定
EventEmitter
的回调执行的线程来实现。
使用
threads.disposable()
可以简单地等待和获取某个线程的执行结果。例如要等待某个线程计算"1+.....+10000":
var sum = threads.disposable();
threads.start(function(){
var s = 0;
for(var i = 1; i <= 10000; i++){
s += i;
sum.setAndNotify(s);
});
toast("sum = " + sum.blockedGet());
如果上述代码用
Condition
实现:
var lock = threads.lock();
var complete = lock.newCondition();
var sum = 0;
threads.start(function(){
for(var i = 1; i <= 10000; i++){
sum += i;
lock.lock();
complete.signal();
lock.unlock();
});
lock.lock();
complete.await();
lock.unlock();
toast("sum = " + sum);
如果上诉代码用
events
模块实现:
var sum = events.emitter(threads.currentThread());
threads.start(
function(){
var s = 0;
for(var i = 1; i <= 10000; i++){
s += i;
sum.emit('result', s);
});
sum.on('result', function(s){