我有点得到线程的窍门,但现在我很困惑。我完全不理解排队。我创建了一个线程池执行器,它初始化了一组线程,每个线程在网站上输入一个用户名(字符串)来检查它是否可用。所以我想我应该排队吗?如queue.add(username)和queue.remove(username)或queue.take..所以我想知道如何使用线程池和哪种类型的队列。SynchronousQueue, BlockingQueue,还是有更好的替代方案?对不起,我真的不懂排队。忽略坏代码。在我把它设置为net
之前,希望它能正常工作FilterUsers FU = new FilterUsers();
HtmlThread[] threads = new HtmlThread[users.length];
ExecutorService executor = Executors.newFixedThreadPool(threadNo);
for (int i = 0; i < users.length; i++) {
Runnable worker = new HtmlThread(" "+i, FU, users[i]);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()){ }
这是类HtmlThread
class HtmlThread extends Thread {
private Thread t;
private String threadName;
FilterUsers filterUsers;
String users;
public HtmlThread(String tName, FilterUsers filterusers, String user) {
this.threadName = tName;
this.filterUsers = filterusers;
this.users = user;
}
public void run() {
synchronized (filterUsers) {
try {
HtmlPage page = webClient.getPage("https://website.com/account/edit");
try {
final HtmlForm form = page.getFirstByXPath("//form[@class='adjacent bordered']");
HtmlTextInput user = form.getInputByName("username");
HtmlSubmitInput b = form.getInputByValue("Submit");
user.setValueAttribute(users);
HtmlPage page2;
page2 = b.click();
String html = page2.getWebResponse().getContentAsString();
if (page2 != null) {
if (!html.contains("that username is taken")) {
Filter.validUsers.appendText(users + "n");
}
}
} finally {
page.cleanUp();
}
} catch (Exception e) {
e.printStackTrace();
}
}
try {
System.out.println("Thread " + threadName + " Sleeping.");
Thread.sleep(3500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + threadName + " exiting.");
}
哦,您关心的是返回结果。根据你的评论:
我更新了代码。当我这样做的时候,它走得太快了。尽管我让线程休眠3.5秒。我认为它实际上并不睡觉。所以我认为我应该添加队列来防止数据丢失或w/e
你应该在你的问题里说这一点。您可以使用队列,但是Java实际上有它自己的返回数据的机制。你至少应该先试一下。
要返回结果,使用Callable
接口而不是Thread/Runnable。Callable的工作原理和Runnable一样,除了你可以返回一个值。当您向执行器服务提交Callable时,您将获得一个Future
。只需保存它,然后调用get()
来获得结果。就这样,创建队列或同步的所有艰苦工作都已经为您完成了。
唯一剩下的事情是检查InterruptedException
在几乎每一个可以想象的地方。;)
/**
*
* @author Brenden Towey
*/
public class FutureExample
{
public static void main( String[] args )
{
ExecutorService exe = Executors.newFixedThreadPool(3);
List<Future<String>> results = new ArrayList<>();
for( int i = 0; i < 5; i++ )
results.add( exe.submit( new HtmlTask() ) );
try {
for( Future<String> future : results )
System.out.println( future.get() );
} catch( InterruptedException x ) {
// bail
} catch( ExecutionException ex ) {
Logger.getLogger( FutureExample.class.getName() ).
log( Level.SEVERE, null, ex );
// and bail
}
exe.shutdown();
boolean shutdown = false;
try {
shutdown = exe.awaitTermination(10 , TimeUnit.SECONDS );
} catch( InterruptedException ex ) {
// bail
}
if( !shutdown ) {
exe.shutdownNow();
try {
exe.awaitTermination( 30, TimeUnit.SECONDS );
} catch( InterruptedException ex ) {
// just exit
}
}
}
}
class HtmlTask implements Callable<String> {
@Override
public String call()
throws Exception
{
// pretend to search a website and return some result
return "200 OK";
}
}
队列的概念是生产者和消费者。生产者将项目放在队列中,消费者线程(通常是多个线程)获取项目并对其进行处理。
SynchronousQueue
-是一个队列,在put()
返回之前必须对take()
进行相应的调用。
BlockingQueue
-是一个接口。SynchronousQueue
是BlockingQueue
所以现在你可能很困惑。我怀疑你是否需要SynchQueue
。我建议您首先阅读BlockingQueue的javadoc。
就个人而言,您可能希望使用ArrayBlockingQueue
。您应该提供容量。否则,如果生产者将更多的项目放在队列中,那么您将耗尽内存。
我真的不明白你为什么要在filterUsers上同步。进入同步代码块的线程如何修改filterUsers?假设filterUsers是某种类型的List实现(这里似乎不是这种情况),您需要对其进行同步,以便在放入或获取元素时线程阻塞,您可以使用BlockingQueue来摆脱同步代码块。BlockingQueue将在size()达到容量时阻塞所有执行put()的线程,直到使用take()删除元素。所以,除非你的同步代码块是在一个需要阻塞的列表上,否则阻塞队列是不会有帮助的。