通知后的Java释放锁定会导致出现新线程

时间:2014-12-22 16:37:13

标签: java multithreading notify

![在这里输入图像描述] [1]有没有人知道为什么在notifyall之后释放锁时会创建新线程? 我有一个线程正在侦听请求状态(STRING)以进行更改(等待锁定对象),另一个线程正在更改它:

@Override
public void run() {
    while(!customerGroupDetails.isEmpty()){
        RentalRequest request=customerGroupDetails.remove();
        management.addRentalRequest(request);
        getLogger().info(Thread.currentThread().getName() + ": handling new request:" + request.toString());
        getLogger().info(Thread.currentThread().getName() + ": waiting for request status to be FULFILLED");
        request.waitForStatus("FULFILLED");
        ExecutorService ex=Executors.newCachedThreadPool();
        CompletionService<Double> cs= new ExecutorCompletionService<Double>(ex);
        CreateStaySimulationForClient stay=new CreateStaySimulationForClient(cs,request.getDuration());
        request.setRequestStatus("INPROGRESS");
        getLogger().info(Thread.currentThread().getName() + ": Simulating stay and setting requets status to INPROGRESS");
        customerGroupDetails.forEach(stay);
        Future<Double> damage=null;
        Double recivedDamage=new Double(0);
        double sum=0;
        int numberOfCustomers=customerGroupDetails.size();
        for(int i=0;i<numberOfCustomers;i++){
            try {
                damage=cs.take();
                recivedDamage=damage.get();
                getLogger().info(" damage for assetContent is " + recivedDamage);
                sum=sum+recivedDamage;



            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        getLogger().info(Thread.currentThread().getName() + ": Asset is damaged by " + sum);
        request.getAsset().damage(sum);
        if(request.getAsset().getHealth()<65){
            management.changeAssetStatus(request.getAsset(), "UNAVILABLE");
            DamageReport damageReport=new DamageReport(request.getAsset(), sum);
            management.addDamageReport(damageReport);
        }
        else{
            management.changeAssetStatus(request.getAsset(), "AVAILABLE");
            getLogger().info(request.getAsset() + " is now available");
        }

        request.setRequestStatus("COMPLETE");
        getLogger().info(Thread.currentThread().getName() + ": damage report has been submitted to managment - this request status is COMPLETE");

    }
    getLogger().info(Thread.currentThread().getName() + ": no more requests for me - i'm done");

}

@Override
public void run() {
    int totalTime = 0;
    boolean shiftEnded = false;
    getLogger().info(clerkDetails.toString() + ": starting new shift");
    while (!shiftEnded&& !Thread.currentThread().isInterrupted()) {
        RentalRequest req = null;
        getLogger().info(clerkDetails.toString() + ": trying to take request");
        try {
            req = rentalRequests.take();
        } catch (InterruptedException e) {
            if (numberOfRequests.get() == 0) {
                getLogger()
                        .info(clerkDetails.toString()
                                + " was interrupted becuase there are no more requests");
                shiftEnded=true;
            } else {
                getLogger().warning(
                        clerkDetails.toString()
                                + " was interrupted unexpectedly"
                                + e.toString());

            }
        }
        if (req!=null) {
            int num=numberOfRequests.decrementAndGet();
            getLogger().info(clerkDetails.toString() + ": recived request: "+req.toString()+",number of requests left is " +num +", now finding appropreiate asset");
            Asset asset = assets.getAsset(req.getAssetType(),
                    req.getAssetSize());
            assets.changeAssetStatus(asset, "BOOKED");

            getLogger().info(clerkDetails.toString() + ": Asset " + asset.toString() + " is now BOOKED");
            req.setAsset(asset);

            management.updateEarnings(asset.getCostPerNight()
                    * req.getDuration());

            int time = getClerkDetails().getLocation().calculateDistance(
                    asset.getLocation());
            totalTime = totalTime + time;
            getLogger().info(clerkDetails.toString() + ": going to Asset - sleeping:" + time);

            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                getLogger().warning(
                        clerkDetails.toString()
                                + " was interrupted unexpectedly"
                                + e.toString());



            }

            req.setRequestStatus("FULFILLED");

            getLogger().info(clerkDetails.toString() + ": request status set to: FULFILLED");
            getLogger().info(clerkDetails.toString()  +": time left for this shift is " + (8 -totalTime));

            if (totalTime > 8) {
                shiftEnded = true;


            }
            if (numberOfRequests.get() == 0) {
                shiftEnded=true;
                management.interrupt();

                getLogger().info(clerkDetails.toString() + ": finished last requets for this simulation - tyring to interrupet managment");
            }

        }


    }
    management.countDownClerksBarriar();
    getLogger().info(clerkDetails.toString() + ": finished shift");

}

public void setRequestStatus(String status) {
    synchronized(statusLock){
        //if(!getRequestStatus().equalsIgnoreCase(status)){
            requestStatus = status;
            statusLock.notifyAll();
        //}
    }


}
public void waitForStatus(String status){
    synchronized (statusLock) {
    while(!getRequestStatus().equalsIgnoreCase(status)){

            try {
                statusLock.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

一切都按预期工作,除了在发布锁之后创建新线程, 使用visualvm profiler我得到了线程转储,他们都显示:

"pool-15-thread-2" prio=6 tid=0x000000000c20e000 nid=0x23d8 waiting on condition [0x00000000112be000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000e0badf08> (a java.util.concurrent.SynchronousQueue$TransferStack)
    at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
    at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(Unknown Source)
    at java.util.concurrent.SynchronousQueue$TransferStack.transfer(Unknown Source)
    at java.util.concurrent.SynchronousQueue.poll(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

   Locked ownable synchronizers:
    - None

不用说 - 我创建的所有线程都有名字所以我知道它不是其中之一, 我创建的所有线程都已完成 30-40秒后,所有螺纹都会死亡,最后一个过程停止 测试完成以确定原因:

  1. 尝试在带有留言板的较小代码上重现问题 - 一个线程等待字符串改变而另一个线程改变它 - 没有导致问题
  2. 对同一个对象执行notifyall并不会重现问题,如果没有线程等待它
  3. 尝试使用其他对象作为锁定 - 问题主持人
  4. 获取信息:在eclipse上运行的Windows 7 x64上使用jdk1.7.0_71

    任何帮助将不胜感激

1 个答案:

答案 0 :(得分:0)

这一行:ExecutorService ex=Executors.newCachedThreadPool();创建一个线程池。 这一行:CreateStaySimulationForClient stay=new CreateStaySimulationForClient(cs,request.getDuration()); 据推测,使用该线程池创建一些东西。

你在snipped中提到的线程是该池中的一个线程。它确实有一个名字,它有&#34; pool&#34;在其中,以便你知道它来自哪里:)

另外,请注意您在循环中执行此操作(创建线程池),这几乎肯定是您想要执行的操作。