Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在同一资源上以不同方法使用sunchronized块避免竞争条件_Java_Multithreading_Race Condition_Synchronized - Fatal编程技术网

Java 在同一资源上以不同方法使用sunchronized块避免竞争条件

Java 在同一资源上以不同方法使用sunchronized块避免竞争条件,java,multithreading,race-condition,synchronized,Java,Multithreading,Race Condition,Synchronized,我正在编写一个简单的爬虫程序,它从根URL开始保存指定数量的页面。 它使用BFS方法遍历链接。 以下是课程代码: public class SimpleCrawler implements Runnable { private int maxPages; private List<String> visitedPages; private List<String> linksToVisit; private File saveDi

我正在编写一个简单的爬虫程序,它从根URL开始保存指定数量的页面。 它使用BFS方法遍历链接。 以下是课程代码:

    public class SimpleCrawler implements Runnable {

    private int maxPages;
    private List<String> visitedPages;
    private List<String> linksToVisit;
    private File saveDir;
    private int linksOnPage;

    public SimpleCrawler(String rootUrl, File saveDir, List<String> visitedPages, int maxPages, int linksOnPage) {
        linksToVisit = new ArrayList<>();
        linksToVisit.add(rootUrl);
        this.saveDir = saveDir;
        this.visitedPages = visitedPages;
        this.maxPages = maxPages;
        this.linksOnPage = linksOnPage;
    }

    private boolean addUrl(String url) {
        synchronized (visitedPages) {
            return visitedPages.add(url);
        }
    }

    private boolean deleteUrl(String url) {
        synchronized (visitedPages) {
            return visitedPages.remove(url);
        }
    }

    private int getListSize(){
        synchronized (visitedPages){
            return visitedPages.size();
        }
    }

    @Override
    public void run() {
        while (getListSize() < maxPages) {
            String url = linksToVisit.remove(0);
            if (!visitedPages.contains(url)) {
                this.addUrl(url);
            }

            // do my staff
        }
    }
}
公共类SimpleCrawler实现可运行{
私有int-maxPages;
私人列表访问页面;
私人名单链接访问;
私有文件saveDir;
私人int linksOnPage;
公共SimpleCrawler(字符串rootUrl、文件saveDir、列表访问页面、int-maxPages、int-linksOnPage){
linksToVisit=newarraylist();
linksToVisit.add(rootUrl);
this.saveDir=saveDir;
this.visitedPages=已访问页面;
this.maxPages=maxPages;
this.linksOnPage=linksOnPage;
}
私有布尔addUrl(字符串url){
已同步(已访问页面){
返回已访问的页面。添加(url);
}
}
专用布尔删除url(字符串url){
已同步(已访问页面){
返回已访问的页面。删除(url);
}
}
私有int getListSize(){
已同步(已访问页面){
返回visitedPages.size();
}
}
@凌驾
公开募捐{
while(getListSize()
我有一些方法,每个方法都可以捕获共享列表的监视器,并在工作完成后发布。 我认为共享列表的锁定和解锁可能会导致这种情况:

maxPages = 100

Thread1 getListSize() < 100;// listSize = 99
...
Thread2 getListSize() < 100;// listSize = 99
...
Thread1 addUrl(url);// listSize = 100
...
Thread2 addUrl(url);// listSize = 101 while maxPages = 100
maxPages=100
Thread1 getListSize()<100;//listSize=99
...
Thread2 getListSize()<100;//listSize=99
...
Thread1 addUrl(url);//列表大小=100
...
Thread2 addUrl(url);//listSize=101,而maxPages=100
在第一个线程释放监视器之前,第二个线程可以检查大小吗? 或
将这两个操作合并到一个关键部分是否更好?

我认为您可能会发现使用并发队列(如
BlockingQueue
)更容易。这些都是为此类应用程序设计的。正如您所意识到的,列表上的所有读写操作都需要以原子方式处理,因此都发生在同步块中,即getListSize()和addUrl()中两者都需要发生在同一个同步块中。我还将备份列表设为此类私有,并在其中处理所有操作,以防止客户端在没有同步控制的情况下意外操作。感谢您的建议,我犯了一个错误。我想您可能会发现使用并发队列(如
BlockingQueue
)更容易。这些都是为此类应用程序设计的。正如您所意识到的,列表上的所有读写操作都需要以原子方式处理,因此都发生在同步块中,即getListSize()和addUrl()中两者都需要发生在同一个同步块中。我还将备份列表设为该类的私有,并处理其中的所有操作,以防止客户端在没有同步控制的情况下意外操作。谢谢您的建议,我弄错了。