📜  什么是多线程中的滑动条件?

📅  最后修改于: 2022-05-13 01:55:19.649000             🧑  作者: Mango

什么是多线程中的滑动条件?

滑移条件是一种特殊类型的竞争条件,可能发生在多线程应用程序中。在这种情况下,线程在读取条件之后在执行与其相关的活动之前被挂起。它很少发生,但是,如果结果不符合预期,则必须寻找它。

示例:假设有两个线程 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尝试处理字符串,但它不能因为isLockedSlippedThread设置为 true 。