背景:我正在并行运行自动化测试。多个浏览器在相同数量的线程中启动,即1个浏览器即1个线程,并使用pom.xml中的分支。
pom.xml
中的插件在下面创建了与线程(叉)计数相等的Parallel**IT.class
。
所有这些类都一次并行执行。因此,似乎每当我创建volatile variable
或AtomicInteger
时,每个线程都会创建自己的线程,因此在多个线程之间共享变量的概念不起作用。
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin}</version>
<configuration>
<systemPropertyVariables>
<webdriver.base.url>${webdriver.base.url}</webdriver.base.url>
</systemPropertyVariables>
<argLine>
-javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
<forkCount>5</forkCount>
<reuseForks>true</reuseForks>
<includes>
<include>**/Parallel*IT.class</include>
</includes>
<perCoreThreadCount>true</perCoreThreadCount>
<properties>
<property>
<name>listener</name>
<value>ru.yandex.qatools.allure.junit.AllureRunListener</value>
</property>
</properties>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
我只希望1个线程访问“准备测试数据”功能并将flag
设置为false
,而其他线程将flag
视为false
他们不会尝试准备测试数据。
我正在跟踪教程https://www.youtube.com/watch?v=WH5UvQJizH0,以使用synchronization
变量实现volatile
。也许我在犯一些错误,但是所有线程都在打印System.out.println("Preparing test data");
尝试1:不稳定和同步
volatile boolean flag = false;
public synchronized void setFlagTofalse(){
System.out.println("Inside sync block");
this.flag = true;
}
// works before class only once
private EventHandler<TestRunStarted> prepareTestData = event -> {
if(flag==false) {
System.out.println("Preparing test data");
setFlagTofalse();
}
};
尝试2:原子与同步
AtomicInteger flag = new AtomicInteger(0);
private EventHandler<TestRunStarted> prepareTestData = event -> {
if(flag.get()==0) {
System.out.println("Preparing test data");
value.incrementAndGet();
}
答案 0 :(得分:1)
如果您是我,则在访问标志变量时将实现互斥锁。因此,在读取标志的值或更改其值之前,线程必须获取锁。这样,他们永远不会同时读取它,也不会在读取旧值之前写入新值,等等。
编辑:更多说明
@paul解释锁的作用:基本上,它是一个可以被线程抛掷的球。因此,如果您与一群人围成一圈坐下,并且有球,那么该说“ X”了。然后,一旦您说完,就将球放在圆圈的中间,直到那里,直到同一个人或其他人再次想要球,然后接住球或等到球可用为止,然后再说“ X”。在您的情况下,线程必须具有锁才能更改或读取变量标志,因此您将要做的是:
Mutex lock = new Mutex();
lock.aquire();
if ( flag == something ){
//do something
}
mutex.release()
或者如果您要更改标志。
lock.aquire();
flag = something;
lock.release();
如您所见,锁在线程之间共享。因此,它是在管理线程的类中创建的,然后传递给在线程中启动的Runnable对象或方法。
所以:
Mutex lock = new Mutex();
Runnable1 r1 = new Runnable1(lock);
Runnable2 r2 = new Runnable2(lock);
//use the lock in the methods of t1 and t2 that use your volitile var
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
//the join wait for completion of the runnable method in your class.
t1.join();
t2.join();
祝你好运:)
答案 1 :(得分:0)
如果您进行测试(flag.get()== 0)和一个操作,则您将两个同步。只需将整个prepareTestData方法标记为同步?
答案 2 :(得分:0)
您同步了错误的方法。您可以尝试这样的方法:
volatile boolean flag = false;
public void setFlagTofalse(){
System.out.println("Inside sync block");
this.flag = true;
}
// works before class only once
private EventHandler<TestRunStarted> prepareTestData = event -> prepareData();
private synchronized void prepareData() {
if(!flag) {
System.out.println("Preparing test data");
setFlagTofalse();
}
//prepare data here
}
答案 3 :(得分:0)
“标志”和“ lockObject”必须为“静态”,以便每个对象只有一个实例。尽管如果您有单例对象,则不必为“标志”使用“静态”,但“ lockObject”应为静态。
此外,在“ prepareTestData”中使用“ lockObject”进行同步。这表明Java到此为止,只有一个线程可以访问该代码。一旦一个线程进入内部,其他线程将等待该线程返回后再进入。
private static Object lockObject = new Object();
private static Boolean flag = Boolean.FALSE;
private void prepareTestData() {
synchronized(lockObject) { //This will keep other threads waiting
if(!flag) {
//prepare data
flag = Boolean.TRUE;
}
}
}
希望这会回答您的问题。