{"action":"created","comment":{"url":"https://api.github.com/repos/threadly/threadly/pulls/comments/42878452","id":42878452,"diff_hunk":"@@ -812,101 +731,204 @@ public int getCurrentRunningCount() {\n      * Ensures all threads have been started.  This will make new idle workers to accept tasks.\n      */\n     public void prestartAllThreads() {\n-      synchronized (workersLock) {\n-        boolean startedThreads = false;\n-        while (currentPoolSize < maxPoolSize) {\n-          availableWorkers.addFirst(makeNewWorker());\n-          startedThreads = true;\n-        }\n-        \n-        if (startedThreads) {\n-          workersLock.notifyAll();\n-        }\n-      }\n-    }\n-    \n-    /**\n-     * Call to get (or create, if able to) an idle worker.  If there are no idle workers available \n-     * then this call will block until one does become available.\n-     * \n-     * @return A worker ready to accept a task or {@code null} if the pool was shutdown\n-     * @throws InterruptedException Thrown if this thread is interrupted while waiting to acquire a worker\n-     */\n-    public Worker getWorker() throws InterruptedException {\n-      synchronized (workersLock) {\n-        while (availableWorkers.isEmpty() && ! shutdownFinishing) {\n-          if (currentPoolSize < maxPoolSize) {\n-            return makeNewWorker();\n-          } else {\n-            waitingForWorker = true;\n-            try {\n-              workersLock.wait();\n-            } finally {\n-              waitingForWorker = false;\n-            }\n-          }\n+      int casPoolSize;\n+      while ((casPoolSize = currentPoolSize.get()) < maxPoolSize) {\n+        if (currentPoolSize.compareAndSet(casPoolSize, casPoolSize + 1)) {\n+          makeNewWorker();\n         }\n-        \n-        return availableWorkers.poll();\n       }\n     }\n     \n     /**\n-     * This function REQUIRES that workersLock is synchronized before calling.  This call creates \n-     * a new worker, starts it, but does NOT add it as an available worker (so you can immediately \n-     * use it).  If you want this worker to be available for other tasks, it must be added to the \n-     * {@code availableWorkers} queue.\n-     * \n-     * @return Newly created worker, started and ready to accept work\n+     * This call creates and starts a new worker.  It does not modify {@link currentPoolSize} so \n+     * that MUST be updated in a thread safe way before this is invoked.  As soon as the worker \n+     * starts it will attempt to start taking tasks, no further action is needed.\n      */\n-    protected Worker makeNewWorker() {\n+    protected void makeNewWorker() {\n       Worker w = new Worker(this, threadFactory);\n-      currentPoolSize++;\n       w.start();\n-      \n-      // will be added to available workers when done with first task\n-      return w;\n     }\n     \n     /**\n-     * Shuts down the worker and ensures this now dead worker wont be used.\n+     * Adds a worker to the head of the idle worker chain.\n      * \n-     * @param w worker to shutdown\n+     * @param worker Worker that is ready to become idle\n      */\n-    protected void killWorker(Worker w) {\n-      // IMPORTANT** if this lock is removed, it is important to read the comment bellow\n-      synchronized (workersLock) {\n-        /* this will throw an exception if the worker has already stopped, \n-         * we want to ensure the pool size is not decremented more than once for a given worker.\n-         * \n-         * We are able to stop first, because we are holding the workers lock.  In the future if we \n-         * try to reduce locking around here, we need to ensure that the worker is removed from the \n-         * available workers BEFORE stopping.\n-         */\n-        w.stopIfRunning();\n-        currentPoolSize--;\n-        // it may not always be here, but it sometimes can (for example when a worker is interrupted)\n-        availableWorkers.remove(w);\n+    protected void addWorkerToIdleChain(Worker worker) {","path":"src/main/java/org/threadly/concurrent/PriorityScheduler.java","position":549,"original_position":549,"commit_id":"50e2dcf9a4a527563e5be92a9c9ab5a8dad4ffe4","original_commit_id":"10b6d473e4a5f831976dc766b0f6939da74e7371","user":{"login":"lwahlmeier","id":4663016,"avatar_url":"https://avatars.githubusercontent.com/u/4663016?v=3","gravatar_id":"","url":"https://api.github.com/users/lwahlmeier","html_url":"https://github.com/lwahlmeier","followers_url":"https://api.github.com/users/lwahlmeier/followers","following_url":"https://api.github.com/users/lwahlmeier/following{/other_user}","gists_url":"https://api.github.com/users/lwahlmeier/gists{/gist_id}","starred_url":"https://api.github.com/users/lwahlmeier/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lwahlmeier/subscriptions","organizations_url":"https://api.github.com/users/lwahlmeier/orgs","repos_url":"https://api.github.com/users/lwahlmeier/repos","events_url":"https://api.github.com/users/lwahlmeier/events{/privacy}","received_events_url":"https://api.github.com/users/lwahlmeier/received_events","type":"User","site_admin":false},"body":"Interesting design.  Does this run into any issues spinning a lot when the idleWorker is under a lot of contention? ","created_at":"2015-10-23T15:29:02Z","updated_at":"2015-10-23T15:29:02Z","html_url":"https://github.com/threadly/threadly/pull/184#discussion_r42878452","pull_request_url":"https://api.github.com/repos/threadly/threadly/pulls/184","_links":{"self":{"href":"https://api.github.com/repos/threadly/threadly/pulls/comments/42878452"},"html":{"href":"https://github.com/threadly/threadly/pull/184#discussion_r42878452"},"pull_request":{"href":"https://api.github.com/repos/threadly/threadly/pulls/184"}}},"pull_request":{"url":"https://api.github.com/repos/threadly/threadly/pulls/184","id":48518974,"html_url":"https://github.com/threadly/threadly/pull/184","diff_url":"https://github.com/threadly/threadly/pull/184.diff","patch_url":"https://github.com/threadly/threadly/pull/184.patch","issue_url":"https://api.github.com/repos/threadly/threadly/issues/184","number":184,"state":"open","locked":false,"title":"PriorityScheduler: remove the queue manager thread","user":{"login":"jentfoo","id":2165757,"avatar_url":"https://avatars.githubusercontent.com/u/2165757?v=3","gravatar_id":"","url":"https://api.github.com/users/jentfoo","html_url":"https://github.com/jentfoo","followers_url":"https://api.github.com/users/jentfoo/followers","following_url":"https://api.github.com/users/jentfoo/following{/other_user}","gists_url":"https://api.github.com/users/jentfoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jentfoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jentfoo/subscriptions","organizations_url":"https://api.github.com/users/jentfoo/orgs","repos_url":"https://api.github.com/users/jentfoo/repos","events_url":"https://api.github.com/users/jentfoo/events{/privacy}","received_events_url":"https://api.github.com/users/jentfoo/received_events","type":"User","site_admin":false},"body":"This is a large change that is really the sum of months of work.\r\nThis removes the queue manager thread.  Workers never move into an idle structure.  Instead each worker tries to aggressively take tasks.  A lot more similar to how java.util's schedulers work, but with quite a few complexities due to how threadly works.\r\nThis provides a massive performance improvement.  But also still has some problems I am yet to figure out solutions for (documented as TODO).\r\n\r\nBecause of the complexity and the risk of this change I will describe things in-line (sorry for the spam to all the watchers of the project).\r\n\r\nDon't merge this until we know we are all okay with everything.","created_at":"2015-10-22T22:00:19Z","updated_at":"2015-10-23T15:29:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"60b1531c81cefc84ca8b62d4063e8cbe5c2f76ae","assignee":null,"milestone":{"url":"https://api.github.com/repos/threadly/threadly/milestones/37","html_url":"https://github.com/threadly/threadly/milestones/4.4.0%20Release","labels_url":"https://api.github.com/repos/threadly/threadly/milestones/37/labels","id":1308482,"number":37,"title":"4.4.0 Release","description":"Changes included in this release:\r\n\r\n* Added AbstractFutureCallbackFailureHandler, AbstractFutureCallbackResultHandler, FutureCallbackExceptionHandlerAdapter.  These implementations are just to reduce boiler plate code.  Allowing you to create FutureCallback implementations which care for just the result, or just the failure condition.\r\n* Added tuple classes \"Pair\" and \"MutablePair\".  I find myself wanting these from time to time, the latest being in ambush.  So I added them as a little utility class.\r\n* Switched RunnableListenerHelper and ListenerHelper to use a list of \"Pair\"'s described above instead of a HashMap.  This has a sizable improvement of both listener add time, and the amount of heap used.  Though it does mean if a listener is added multiple times it will be invoked multiple times (where previously just the last addition was used).  Please see the discussion on #177 for more information, and the change can be seen in PR #179.\r\n* Added Clock.accurateNanoTime() and Clock.lastKnownNanoTime().  Allowing access to the stored nano time without the conversion to milliseconds.\r\n* Improved ExecutorService wrappers for invokeAll when no timeout is provided, we now avoid clock calls during that case.\r\n* Fixed issue where sending a thread interrupt to a unit test thread can cause TestCondition to spin loop (without parking).\r\n* Deprecated Clock.systemNanoTime, instead use Clock.accurateNanoTime\r\n* Deprecated AbstractDelayed.  Since this abstract implementation has no meaningful value inside threadly, and because it likely only would have value to other pool developers it does not seem worth the jar size.  If anyone is actually using this let me know via a github issue and lets discuss.\r\n* Deprecated (Abstract)PriorityScheduler.makeWithDefaultPriority.  We are trying to stop sprinkling these helper/wrapper functions everywhere.  Instead to keep things more concise and uniform you should manually wrap the scheduler in a PrioritySchedulerDefaultPriorityWrapper","creator":{"login":"jentfoo","id":2165757,"avatar_url":"https://avatars.githubusercontent.com/u/2165757?v=3","gravatar_id":"","url":"https://api.github.com/users/jentfoo","html_url":"https://github.com/jentfoo","followers_url":"https://api.github.com/users/jentfoo/followers","following_url":"https://api.github.com/users/jentfoo/following{/other_user}","gists_url":"https://api.github.com/users/jentfoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jentfoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jentfoo/subscriptions","organizations_url":"https://api.github.com/users/jentfoo/orgs","repos_url":"https://api.github.com/users/jentfoo/repos","events_url":"https://api.github.com/users/jentfoo/events{/privacy}","received_events_url":"https://api.github.com/users/jentfoo/received_events","type":"User","site_admin":false},"open_issues":2,"closed_issues":5,"state":"open","created_at":"2015-09-16T13:50:21Z","updated_at":"2015-10-22T22:42:27Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/threadly/threadly/pulls/184/commits","review_comments_url":"https://api.github.com/repos/threadly/threadly/pulls/184/comments","review_comment_url":"https://api.github.com/repos/threadly/threadly/pulls/comments{/number}","comments_url":"https://api.github.com/repos/threadly/threadly/issues/184/comments","statuses_url":"https://api.github.com/repos/threadly/threadly/statuses/50e2dcf9a4a527563e5be92a9c9ab5a8dad4ffe4","head":{"label":"jentfoo:PriorityScheduler-no_queue_manager_thread","ref":"PriorityScheduler-no_queue_manager_thread","sha":"50e2dcf9a4a527563e5be92a9c9ab5a8dad4ffe4","user":{"login":"jentfoo","id":2165757,"avatar_url":"https://avatars.githubusercontent.com/u/2165757?v=3","gravatar_id":"","url":"https://api.github.com/users/jentfoo","html_url":"https://github.com/jentfoo","followers_url":"https://api.github.com/users/jentfoo/followers","following_url":"https://api.github.com/users/jentfoo/following{/other_user}","gists_url":"https://api.github.com/users/jentfoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jentfoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jentfoo/subscriptions","organizations_url":"https://api.github.com/users/jentfoo/orgs","repos_url":"https://api.github.com/users/jentfoo/repos","events_url":"https://api.github.com/users/jentfoo/events{/privacy}","received_events_url":"https://api.github.com/users/jentfoo/received_events","type":"User","site_admin":false},"repo":{"id":11236509,"name":"threadly","full_name":"jentfoo/threadly","owner":{"login":"jentfoo","id":2165757,"avatar_url":"https://avatars.githubusercontent.com/u/2165757?v=3","gravatar_id":"","url":"https://api.github.com/users/jentfoo","html_url":"https://github.com/jentfoo","followers_url":"https://api.github.com/users/jentfoo/followers","following_url":"https://api.github.com/users/jentfoo/following{/other_user}","gists_url":"https://api.github.com/users/jentfoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jentfoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jentfoo/subscriptions","organizations_url":"https://api.github.com/users/jentfoo/orgs","repos_url":"https://api.github.com/users/jentfoo/repos","events_url":"https://api.github.com/users/jentfoo/events{/privacy}","received_events_url":"https://api.github.com/users/jentfoo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jentfoo/threadly","description":"A library of tools to assist with concurrent java development, with a large focus on testability.","fork":true,"url":"https://api.github.com/repos/jentfoo/threadly","forks_url":"https://api.github.com/repos/jentfoo/threadly/forks","keys_url":"https://api.github.com/repos/jentfoo/threadly/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jentfoo/threadly/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jentfoo/threadly/teams","hooks_url":"https://api.github.com/repos/jentfoo/threadly/hooks","issue_events_url":"https://api.github.com/repos/jentfoo/threadly/issues/events{/number}","events_url":"https://api.github.com/repos/jentfoo/threadly/events","assignees_url":"https://api.github.com/repos/jentfoo/threadly/assignees{/user}","branches_url":"https://api.github.com/repos/jentfoo/threadly/branches{/branch}","tags_url":"https://api.github.com/repos/jentfoo/threadly/tags","blobs_url":"https://api.github.com/repos/jentfoo/threadly/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jentfoo/threadly/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jentfoo/threadly/git/refs{/sha}","trees_url":"https://api.github.com/repos/jentfoo/threadly/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jentfoo/threadly/statuses/{sha}","languages_url":"https://api.github.com/repos/jentfoo/threadly/languages","stargazers_url":"https://api.github.com/repos/jentfoo/threadly/stargazers","contributors_url":"https://api.github.com/repos/jentfoo/threadly/contributors","subscribers_url":"https://api.github.com/repos/jentfoo/threadly/subscribers","subscription_url":"https://api.github.com/repos/jentfoo/threadly/subscription","commits_url":"https://api.github.com/repos/jentfoo/threadly/commits{/sha}","git_commits_url":"https://api.github.com/repos/jentfoo/threadly/git/commits{/sha}","comments_url":"https://api.github.com/repos/jentfoo/threadly/comments{/number}","issue_comment_url":"https://api.github.com/repos/jentfoo/threadly/issues/comments{/number}","contents_url":"https://api.github.com/repos/jentfoo/threadly/contents/{+path}","compare_url":"https://api.github.com/repos/jentfoo/threadly/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jentfoo/threadly/merges","archive_url":"https://api.github.com/repos/jentfoo/threadly/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jentfoo/threadly/downloads","issues_url":"https://api.github.com/repos/jentfoo/threadly/issues{/number}","pulls_url":"https://api.github.com/repos/jentfoo/threadly/pulls{/number}","milestones_url":"https://api.github.com/repos/jentfoo/threadly/milestones{/number}","notifications_url":"https://api.github.com/repos/jentfoo/threadly/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jentfoo/threadly/labels{/name}","releases_url":"https://api.github.com/repos/jentfoo/threadly/releases{/id}","created_at":"2013-07-07T16:52:34Z","updated_at":"2015-05-04T00:53:24Z","pushed_at":"2015-10-23T01:11:21Z","git_url":"git://github.com/jentfoo/threadly.git","ssh_url":"git@github.com:jentfoo/threadly.git","clone_url":"https://github.com/jentfoo/threadly.git","svn_url":"https://github.com/jentfoo/threadly","homepage":"threadly.org","size":6336,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"threadly:unstable_staging","ref":"unstable_staging","sha":"2b9efdfe0dd99595e0df2466f47420022c7bd78f","user":{"login":"threadly","id":4627301,"avatar_url":"https://avatars.githubusercontent.com/u/4627301?v=3","gravatar_id":"","url":"https://api.github.com/users/threadly","html_url":"https://github.com/threadly","followers_url":"https://api.github.com/users/threadly/followers","following_url":"https://api.github.com/users/threadly/following{/other_user}","gists_url":"https://api.github.com/users/threadly/gists{/gist_id}","starred_url":"https://api.github.com/users/threadly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/threadly/subscriptions","organizations_url":"https://api.github.com/users/threadly/orgs","repos_url":"https://api.github.com/users/threadly/repos","events_url":"https://api.github.com/users/threadly/events{/privacy}","received_events_url":"https://api.github.com/users/threadly/received_events","type":"Organization","site_admin":false},"repo":{"id":9874976,"name":"threadly","full_name":"threadly/threadly","owner":{"login":"threadly","id":4627301,"avatar_url":"https://avatars.githubusercontent.com/u/4627301?v=3","gravatar_id":"","url":"https://api.github.com/users/threadly","html_url":"https://github.com/threadly","followers_url":"https://api.github.com/users/threadly/followers","following_url":"https://api.github.com/users/threadly/following{/other_user}","gists_url":"https://api.github.com/users/threadly/gists{/gist_id}","starred_url":"https://api.github.com/users/threadly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/threadly/subscriptions","organizations_url":"https://api.github.com/users/threadly/orgs","repos_url":"https://api.github.com/users/threadly/repos","events_url":"https://api.github.com/users/threadly/events{/privacy}","received_events_url":"https://api.github.com/users/threadly/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/threadly/threadly","description":"A library of tools to assist with safe concurrent java development.  Providing a unique priority based thread pool, and ways to distrbute threaded work safely.","fork":false,"url":"https://api.github.com/repos/threadly/threadly","forks_url":"https://api.github.com/repos/threadly/threadly/forks","keys_url":"https://api.github.com/repos/threadly/threadly/keys{/key_id}","collaborators_url":"https://api.github.com/repos/threadly/threadly/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/threadly/threadly/teams","hooks_url":"https://api.github.com/repos/threadly/threadly/hooks","issue_events_url":"https://api.github.com/repos/threadly/threadly/issues/events{/number}","events_url":"https://api.github.com/repos/threadly/threadly/events","assignees_url":"https://api.github.com/repos/threadly/threadly/assignees{/user}","branches_url":"https://api.github.com/repos/threadly/threadly/branches{/branch}","tags_url":"https://api.github.com/repos/threadly/threadly/tags","blobs_url":"https://api.github.com/repos/threadly/threadly/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/threadly/threadly/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/threadly/threadly/git/refs{/sha}","trees_url":"https://api.github.com/repos/threadly/threadly/git/trees{/sha}","statuses_url":"https://api.github.com/repos/threadly/threadly/statuses/{sha}","languages_url":"https://api.github.com/repos/threadly/threadly/languages","stargazers_url":"https://api.github.com/repos/threadly/threadly/stargazers","contributors_url":"https://api.github.com/repos/threadly/threadly/contributors","subscribers_url":"https://api.github.com/repos/threadly/threadly/subscribers","subscription_url":"https://api.github.com/repos/threadly/threadly/subscription","commits_url":"https://api.github.com/repos/threadly/threadly/commits{/sha}","git_commits_url":"https://api.github.com/repos/threadly/threadly/git/commits{/sha}","comments_url":"https://api.github.com/repos/threadly/threadly/comments{/number}","issue_comment_url":"https://api.github.com/repos/threadly/threadly/issues/comments{/number}","contents_url":"https://api.github.com/repos/threadly/threadly/contents/{+path}","compare_url":"https://api.github.com/repos/threadly/threadly/compare/{base}...{head}","merges_url":"https://api.github.com/repos/threadly/threadly/merges","archive_url":"https://api.github.com/repos/threadly/threadly/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/threadly/threadly/downloads","issues_url":"https://api.github.com/repos/threadly/threadly/issues{/number}","pulls_url":"https://api.github.com/repos/threadly/threadly/pulls{/number}","milestones_url":"https://api.github.com/repos/threadly/threadly/milestones{/number}","notifications_url":"https://api.github.com/repos/threadly/threadly/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/threadly/threadly/labels{/name}","releases_url":"https://api.github.com/repos/threadly/threadly/releases{/id}","created_at":"2013-05-05T21:38:11Z","updated_at":"2015-10-10T15:08:06Z","pushed_at":"2015-10-23T01:11:23Z","git_url":"git://github.com/threadly/threadly.git","ssh_url":"git@github.com:threadly/threadly.git","clone_url":"https://github.com/threadly/threadly.git","svn_url":"https://github.com/threadly/threadly","homepage":"threadly.org","size":15061,"stargazers_count":42,"watchers_count":42,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":12,"mirror_url":null,"open_issues_count":9,"forks":12,"open_issues":9,"watchers":42,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/threadly/threadly/pulls/184"},"html":{"href":"https://github.com/threadly/threadly/pull/184"},"issue":{"href":"https://api.github.com/repos/threadly/threadly/issues/184"},"comments":{"href":"https://api.github.com/repos/threadly/threadly/issues/184/comments"},"review_comments":{"href":"https://api.github.com/repos/threadly/threadly/pulls/184/comments"},"review_comment":{"href":"https://api.github.com/repos/threadly/threadly/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/threadly/threadly/pulls/184/commits"},"statuses":{"href":"https://api.github.com/repos/threadly/threadly/statuses/50e2dcf9a4a527563e5be92a9c9ab5a8dad4ffe4"}}}}