定义或不定义@groovy

时间:2014-02-17 14:03:28

标签: groovy function

有一个groovy脚本,它定义了一个函数并在多个线程中使用。 我发现它不时会将一些变量值与其他线程混合在一起。 当开发人员忘记声明变量时会出现问题:

def f ( x ) {
  y = "" + x
  println y
}

当开发人员声明变量

时,问题就消失了
def f ( x ) {
  def y = "" + x
  println y
}

在类中,无法使用未定义的变量。

原因是在脚本中,undefined变量充当脚本类的实例变量。实际上,这是可以传递到脚本中的外部变量的绑定。

以下是脚本的一部分,演示了在多个线程中使用未定义变量的问题。

void f(String x){
    y=""+x;  //if you put def at this line it'll work fine
    Thread.sleep(333);
    //usually developers expected that `y` is a local variable, 
    //but without declaration it belongs to script-class
    if( !y.equals(x) ) println("failure: x=$x y=$y");
}

//thead 1 start
Thread.start{
    for(int i=0;i<20;i++){
        f( i.toString() )
        Thread.sleep(100);
    }
}

//thead 2 start
Thread.start{
    for(int i=0;i<20;i++){
        f( i.toString() )
        Thread.sleep(150);
    }
}

//main thread sleep.
Thread.sleep(2000);
println("done");

当x不等于y(字面意思)时,此代码将打印失败

2 个答案:

答案 0 :(得分:2)

使用scriptBaseClass编写编译器配置,以禁止未声明的变量以及脚本自身绑定的使用。

这是基本脚本(我的DefBase.groovy文件):

abstract class NoUndefShallPass extends Script {
  void setProperty(String name, val) { 
    // seems like groovy itself set 'args' in the binding, probably from CL
    assert name == 'args', 
        "Error in '$name'; variables should be declared using 'def'" 
  }
}

def configuration = new org.codehaus.groovy.control.CompilerConfiguration()
configuration.setScriptBaseClass(NoUndefShallPass.class.name)

def shell = new GroovyShell(this.class.classLoader, new Binding(), configuration)


shell.evaluate new File('/tmp/Defing.groovy')

和脚本。如果AssertionError尝试使用绑定,它将抛出setProperty

void f(String x){
    y=""+x;  //if you put def at this line it'll work fine
    Thread.sleep(333);
    if( !y.equals(x) ) println("failure: x=$x y=$y");
}

def t1 = Thread.start{
    20.times { i ->
        f( i.toString() )
        Thread.sleep(100);
    }
}

def t2 = Thread.start{
    20.times { i ->
        f( i.toString() )
        Thread.sleep(150);
    }
}

Thread.sleep(2000);
t1.join()
t2.join()
println("done");

答案 1 :(得分:0)