什么是多线程中的滑动条件?
滑移条件是一种特殊类型的竞争条件,可能发生在多线程应用程序中。在这种情况下,线程在读取条件之后并在执行与其相关的活动之前被挂起。它很少发生,但是,如果结果不符合预期,则必须寻找它。
示例:假设有两个线程 A 和线程 B想要处理字符串S。首先,线程 A启动,它检查是否还有字符要处理,最初整个字符串都可以处理,因此条件为真。现在,线程 A被挂起,线程 B启动。它再次检查条件,结果为真,然后处理整个字符串S。现在,当线程 A再次开始执行时,此时字符串S已完全处理,因此发生错误。这被称为滑倒状态。
在Java中演示滑倒条件的程序
// Java program to demonstrate
// slipped conditions
public class Main {
public static void main(String[] args)
{
ReadingThread readingThread
= new ReadingThread();
SlippedThread slippedThread
= new SlippedThread();
slippedThread.start();
readingThread.start();
}
}
class CommonResource {
static final String string = "Hello";
static int pointerPosition = 0;
}
// Thread to demonstrate a slipped condition
class SlippedThread extends Thread {
@Override
public void run()
{
// Check if any characters
// are left to process
if (CommonResource.pointerPosition
!= CommonResource.string.length()) {
System.out.println("Characters left! "
+ "I can process the string");
// Cause the thread to wait to cause
// a slipped condition
try {
synchronized (this)
{
wait(500);
}
}
catch (InterruptedException e) {
System.out.println(e);
}
try {
while (CommonResource.pointerPosition
< CommonResource.string.length()) {
System.out.println("Thread1 "
+ CommonResource.string
.charAt(
CommonResource
.pointerPosition));
CommonResource.pointerPosition++;
}
}
catch (StringIndexOutOfBoundsException e) {
System.out.println("\nNo more character left"
+ " to process. This is a"
+ " slipped condition");
}
}
}
}
// Thread to process the whole String
class ReadingThread extends Thread {
@Override
public void run()
{
System.out.println("Thread2 trying to "
+ "process the string");
while (CommonResource.pointerPosition
< CommonResource.string.length()) {
System.out.print("Thread2 "
+ CommonResource.string
.charAt(
CommonResource
.pointerPosition));
CommonResource.pointerPosition++;
}
}
}
Characters left! I can process the string
Thread2 trying to process the string
Thread2 H
Thread2 e
Thread2 l
Thread2 l
Thread2 o
No more character left to process. This is a slipped condition
滑动条件问题的解决方案相当简单明了。线程在检查条件后要访问的任何资源都必须由线程锁定,并且只能在线程执行工作后释放。所有的访问都必须同步。
针对上述问题,可以通过锁定 CommonResource 类的 String 对象来消除滑移情况。在这种情况下,线程首先获得访问权并锁定字符串,然后尝试处理字符串。
上例的解决方法
public class Main {
public static void main(String[] args)
{
ReadingThread readingThread
= new ReadingThread();
SlippedThread slippedThread
= new SlippedThread();
slippedThread.start();
readingThread.start();
}
}
class CommonResource {
static final String string = "Hello";
static int pointerPosition = 0;
// A static variable added
// to lock the String object
static boolean isLocked = false;
}
// Thread to demonstrate a slipped condition
class SlippedThread extends Thread {
@Override
public void run()
{
// Check if any characters
// are left to process
if (CommonResource.isLocked
!= true
&& CommonResource.pointerPosition
!= CommonResource.string.length()) {
System.out.println("Characters left! "
+ "I can process the string");
CommonResource.isLocked = true;
// Cause the thread to wait to cause
// a slipped condition
try {
synchronized (this)
{
wait(250);
}
}
catch (InterruptedException e) {
System.out.println(e);
}
try {
while (CommonResource.pointerPosition
< CommonResource.string.length()) {
System.out.println("Thread1 "
+ CommonResource
.string.charAt(
CommonResource
.pointerPosition));
CommonResource.pointerPosition++;
}
}
catch (StringIndexOutOfBoundsException e) {
System.out.println("\nNo more character "
+ "left to process. This is "
+ "a slipped condition");
}
CommonResource.isLocked = false;
}
}
}
// Thread to process the whole String
class ReadingThread extends Thread {
@Override
public void run()
{
System.out.println("Thread2 trying to"
+ " process the string");
if (CommonResource.isLocked == false) {
CommonResource.isLocked = true;
synchronized (this)
{
while (CommonResource.pointerPosition
< CommonResource.string.length()) {
System.out.println("Thread2 "
+ CommonResource.string
.charAt(
CommonResource
.pointerPosition));
CommonResource.pointerPosition++;
}
}
}
CommonResource.isLocked = false;
}
}
输出
Characters left! I can process the string
Thread2 trying to process the string
Thread1 H
Thread1 e
Thread1 l
Thread1 l
Thread1 o
在上面的程序中,一个新的静态布尔成员isLocked被添加到CommonResource 类中。现在,每当一个线程试图处理字符串时,它首先获得锁然后处理它。在这个例子中, SlippedCondition 线程检查isLocked是否为假,是否还有字符串需要处理。如果是,则获取锁,然后等待并最终处理字符串。同时, ReadingThread尝试处理字符串,但它不能因为isLocked被SlippedThread设置为 true 。