2016-09-30 63 views
2

我有一个简单的例子。我想要做的是通过将它排除为2个线程来搜索一个数组列表。这是我的主要代码;中断整体线程

class LinearSearch { 
    public static void main(String args[]) { 
     int list[] = new int[1000]; 
     for (int j = 0; j < list.length; j++) 
      list[j] = (int) (Math.random() * 1000); 

     for (int y : list) 
      System.out.print(y + " "); 
     System.out.println(); 
     System.out.print("Enter number to search for: "); 
     Scanner in = new Scanner(System.in); 
     int x = in.nextInt(); 
     Searcher t = new Searcher(list, 0, 500, x); 
     Searcher t1 = new Searcher(list, 500, 1000, x); 
     t.start(); 
     t1.start(); 
     try { 
      t.join(); 
      t1.join(); 
     } catch (InterruptedException e) { 
     } 
     boolean found = t.getResult() || t1.getResult(); 
     System.out.println("Found = " + found); 
    } 
} 

这是Searcher类;

class Searcher extends Thread { 
    private int f[]; 
    private int lb, ub; 
    private int x; 
    private boolean found; 

    Searcher(int f1[], int a, int b, int x) { 
     f = f1; 
     lb = a; 
     ub = b; 
     this.x = x; 
    } 

    public void run() { 
     int k = lb; 
     found = false; 
     while (k < ub && !found) { 
      if (f[k] == x){ 
       found = true; 
       this.interrupt(); 
      } 
      k++; 
     } 
    } 

    boolean getResult() { 
     return found; 
    } 
} 

我把数组分成两部分,让线程完成它们的工作。问题是,即使一个线程找到号码,另一个线程仍然继续搜索。当我在网上寻找答案时,我发现线程的中断方法。 如果我在我的Searcher Thread类中使用中断方法,它会停止两个线程,或者它会停止发现该数字的实例?

顺便说一句,如果你有除了中断问题的另一种解决方案,请提前告诉我

感谢

+0

你认为中断当前线程会做什么? –

回答

1

调用interrupt()显然不能去,你将需要中断所有的方式线程这是相当费力,而且你不能同时中断所有线程,你应该共享代表状态foundAtomicBoolean,因为所有线程都会立即看到AtomicBoolean上的任何修改,这样所有的线程都会停止迭代一次get()返回true

事情是这样的:

class Searcher extends Thread { 
    ... 
    // Used to know if the current thread was the one who found the result 
    private boolean hasFound; 
    private final AtomicBoolean found; 

    Searcher(AtomicBoolean found, int f1[], int a, int b, int x) { 
     this.found = found; 
     ... 
    } 

    public void run() { 
     int k = lb; 
     while (!found.get() && k < ub) { 
      if (f[k] == x){ 
       found.set(hasFound = true); 
       // Use a break instead to exit from the loop 
       break; 
      } 
      k++; 
     } 
    } 

    boolean getResult() { 
     return hasFound; 
    } 
} 

如果使用Java 8你尽量做到能与Stream API为下一步要做:

boolean found = Arrays.stream(list).parallel().anyMatch(i -> x == i); 
1

中断线程没有做任何东西本身:

while (k < ub && !found) { 
    if (f[k] == x){ 
     found = true; 
     this.interrupt(); 
    } 
    k++; 
} 

所有这些都是在线程上设置一个标志来表示“某事中断了我” - 您不会在任何地方检查该标志,因此没有任何结果。

您可以检查该标志在while循环中后卫:

while (k < ub && !found && !Thread.interrupted()) 

(其中如果设置interrupted将清除该标志的状态;您也可以使用Thread.isInterrupted检查状态,而不将其清除)。

但这里的事情是,你真的不需要中断当前话题 - 你已经知道你发现在这个线程的东西,通过found标志。如果你打算中断任何线程,那就是需要中断的其他线程。因此,您需要参考Searcher课程中的其他线索,以便您可以打断此类话题。

但是,你并不真的需要使用中断都:如果你给两个线程在同一AtomicBoolean,他们可以检查:

while (k < ub && !found.get()) { 
    if (f[k] == x) { 
    found.set(true); 
    } 
    k++; 
} 

使用AtomicBoolean的另一优点是什么除了其中一个搜索者可以停止搜索外 - 您可以通过Thread类的静态方法获得对任何线程的引用,从而允许JVM中任何位置的任何代码中断搜索。

通过使用AtomicBoolean,只有这两个搜索器实例能够停止另一个,因为AtomicBoolean不能从外部获得(好吧,也许它可以通过超级恶毒的方式)。

但是,正如Brian Goetz指出的那样,您不妨使用findAny

1

将您在LinearSearch类中创建的线程存储在数组中,并使它们可以被您的Searcher类访问。只要你的发现被设置为真,杀死所有的线程。此外,在Searcher类中为您的线程提供一个唯一的ID作为ID。

class Searcher extends Thread { 
    private int f[]; 
    private int lb, ub; 
    private int x; 
    private boolean found; 
    private int id; 

    Searcher(int f1[], int a, int b, int x, int id) { 
     f = f1; 
     lb = a; 
     ub = b; 
     this.x = x; 
     this.id = id; 
    } 

    public void run() { 
     int k = lb; 
     found = false; 
     while (k < ub && !found) { 
      if (f[k] == x){ 
       found = true; 
       //this.interrupt(); 
       killAllThreads(); 
      } 
      k++; 
     } 
    } 

    boolean getResult() { 
     return found; 
    } 

    //assuming your class has access to allThreads array somehow. You will have to decide the best way to keep this variable accessible to this class. Handle null pointer exceptions in your run method 

    private void killAllThreads(){ 
      for(int i=0; i<allThreads.length; i++){ 
       if(allThreads[i].id != this.id){ 
        if(allThreads[i] != null) 
         allThreads[i] = null; 
       } 
      } 
    } 
} 

然而,参考here如何安全地杀死线程。

+0

不需要传入线程ID并搜索数组中的线程:只需直接传入对“线程”的引用即可。 –

+0

您将如何检查引用是否与传递的参数相同并存在于数组中?你将不得不超载平等的运营商。 –