有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java中的多线程简单线程问题

除我释放爬虫外,其他情况下均有效:

public void setCrawlerFree(WebCrawler w)
    {
        synchronized(myFreeCrawlers)
        {
            synchronized(numToGo)
            {
                myFreeCrawlers.add(w);
                myFreeCrawlers.notifyAll();
                numToGo--;
                numToGo.notify();
            }
        }
    }

当爬虫程序完成后,我可以将其添加回列表中。我还想从我仍然需要做的事情中减去1。我有一个主线程在等待numToGo为0。我在numToGo上得到一个非法监视器状态例外。notify()但是由于它在同步块中,这不意味着我拥有它吗


共 (5) 个答案

  1. # 1 楼答案

    So I thought I needed to call wait and notify on the object that all the threads have in common, but that's not correct either.

    是的。但是:

    public class IllegalMonitorStateException
    extends RuntimeException
    

    Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

    在调用对象上的wait()notify()之前,需要对对象进行同步

  2. # 2 楼答案

    您的numToGo字段是否是正在包装的基本类型?(int到整数、long到long等)。请记住,这些包装是不可变的,每次装箱/取消装箱时都会导致您拥有不同的对象。当需要同步时,始终建议使用最终对象

    而不是使用和integer创建自己的对象来维护值和同步

    
    class Counter {
        private int value ;
        private final Object lock = new Object() ;
    
        public ExecutionStatus() { }
    
        public void increment() {
            synchronized(lock) {
                value ++ ;
            }
        }
    
        public void decrease() {
            synchronized(lock) {
                value-- ;
            }
        }
    
        // Read dirty
        public int count() {
            return value ;
        }
    
        public int safeCount() {
            synchronize(lock) {
                return count() ;
            }
        }
    }
    

    尽管如此,您仍然可以将private final Object lock = new Object()行添加到当前代码中,并使用它来控制numToGo变量的同步

    希望这有帮助

  3. # 3 楼答案

    那里有些好帖子,有很多选择,但我想这是某种学术活动?正如人们所指出的,如果有更现代化的替代方案使事情变得更简单,您可能不会使用wait/notify/notifyAll。不过,wait/notify这件事很有趣,值得作为并发工作的基础来理解

    我假设这是某种消费者/生产者的事情?一个线程正在捕获爬虫,另一个线程正在释放它?如果是这样的话,你可能想在释放之前等待陷阱里有人?它可能看起来像这样

      private final List<Object> trap = new ArrayList<Object>();
    
        public class BugCatcher {
            public void trapCrawler(Object crawler) {
                synchronized (trap) {
                    trap.add(crawler);
                    System.out.println("caught bug number " + trap.size() + "!");
                    trap.notifyAll();
                }
            }
        }
    
        public class Hippy {
            public void setCrawlerFree(Object crawler) throws InterruptedException {
                synchronized (trap) {
                    trap.wait();
                    trap.clear();
                    System.out.println("set bugs free! time to hug a tree");
                }
            }
        }
    

    如果BugCatcher捕获bug的速度比嬉皮士释放bug的速度快,那么嬉皮士会在尝试释放bug之前等待陷阱中有东西(因此wait调用)

    如果省略wait/notify部分,事情将只依赖于synchronized关键字,一次只有一个线程将访问陷阱,这是一场比赛,谁先到达那里(嬉皮士可能会尝试一个空的或已经空的陷阱)

    为了协调等待和通知,VM将使用对象监视器。线程在进入同步块时获取对象的监视器。一个对象只有一个监视器,充当互斥锁(互斥锁)。如果您没有首先获取对象的监视器(没有在同步块中执行waitnotify),就尝试执行waitnotify,那么VM无法进行设置,因此抛出IllegalMonitorException。它的意思是“我不能允许这样做,因为如果,例如,我等待,当有人打电话通知我时,我什么时候知道我可以进步?他们在通知什么/谁?”。它使用监视器进行协调,从而强制您获取监视器

    因此,您得到的错误是因为numToGo没有在另一个线程中同步(正如Michael之前所说的)

    我不太明白你为什么需要numToGo,如果它是生产者/消费者,你想在某个数字之后停止吗?在捕虫员捕捉到10只虫子,嬉皮士释放10只虫子之后?这听起来不像是你想要做的(因为它们可能都有不相关的内部计数器),所以我不确定你想要做什么。如果我完全偏离了正切,那么最好能概括出你想要做的事情

  4. # 4 楼答案

    考虑重写为{a1}。

    ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, 
         maximumPoolSize, keepAliveTime, timeUnit, 
         new LinkedBlockingQueue<Runnable>());
    executor.submit(new Callable<...>() { ... });
    

    它将极大地简化代码并消除线程同步问题

  5. # 5 楼答案

    您正在对非最终成员变量进行同步。您的sync(numToGo)在numToGo的某个值上进行同步,然后更改引用:numToGo--。现在,您有了一个调用notify的不同实例,因此出现了异常