{"id":22513443,"url":"https://github.com/emahtab/fork-join","last_synced_at":"2025-03-28T01:23:47.937Z","repository":{"id":79525506,"uuid":"433283326","full_name":"eMahtab/fork-join","owner":"eMahtab","description":"Fork Join Framework in Java","archived":false,"fork":false,"pushed_at":"2024-11-01T14:48:48.000Z","size":122,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-02T03:19:13.698Z","etag":null,"topics":["concurrency","fork-join-framework","java","work-stealing"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eMahtab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-30T03:45:19.000Z","updated_at":"2024-11-01T14:48:52.000Z","dependencies_parsed_at":"2023-05-10T17:16:17.223Z","dependency_job_id":null,"html_url":"https://github.com/eMahtab/fork-join","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eMahtab%2Ffork-join","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eMahtab%2Ffork-join/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eMahtab%2Ffork-join/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eMahtab%2Ffork-join/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eMahtab","download_url":"https://codeload.github.com/eMahtab/fork-join/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245950639,"owners_count":20699103,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","fork-join-framework","java","work-stealing"],"created_at":"2024-12-07T03:12:22.474Z","updated_at":"2025-03-28T01:23:47.909Z","avatar_url":"https://github.com/eMahtab.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fork Join\n\nThe fork/join framework provides support for parallel programming by splitting up a task into smaller tasks to process them using the available CPU cores.\n\nIn fact, Java 8's parallel streams and the method Arrays#parallelSort use under the hood the fork/join framework to execute parallel tasks.\n\n**Applying a divide and conquer principle**, the framework recursively divides the task into smaller subtasks until a given threshold is reached. This is the fork part.\n\nThen, the subtasks are processed independently and if they return a result, all the results are recursively combined into a single result. This is the join part.\n\n\n![Fork Join](fork-join.gif?raw=true)\n\n\nTo execute the tasks in parallel, the framework uses a pool of threads, with a number of threads equal to the number of processors available to the Java Virtual Machine (JVM) by default.\n\n**💥💥💥 Note :**\n\nEach thread has its own double-ended queue (deque) to store the tasks that will execute.\n\nA deque is a type of queue that supports adding or removing elements from either the front (head) or the back (tail). This allows two things:\n\nA thread can execute only one task at a time (the task at the head of its deque).\nA work-stealing algorithm is implemented to balance the thread’s workload.\nWith the work-stealing algorithm, threads that run out of tasks to process can steal tasks from other threads that are still busy (by removing tasks from the tail of their deque).\n\n\n## RecursiveTask : returns result, have both fork and join part\n```java\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.ForkJoinTask;\nimport java.util.concurrent.RecursiveTask;\n\nclass MyRecursiveTask extends RecursiveTask\u003cInteger\u003e {\n    private int workLoad = 0;\n    public MyRecursiveTask(int workLoad) {\n        this.workLoad = workLoad;\n    }\n\n    protected Integer compute() {\n        // if work is above threshold, break tasks up into smaller tasks\n        if (this.workLoad \u003e 16) {\n            System.out.println(\"Splitting workLoad : \" + this.workLoad);\n            int workload1 = this.workLoad / 2;\n            int workload2 = this.workLoad - workload1;\n            MyRecursiveTask subtask1 = new MyRecursiveTask(workload1);\n            MyRecursiveTask subtask2 = new MyRecursiveTask(workload2);\n            subtask1.fork();\n            subtask2.fork();\n\n            return subtask1.join() + subtask2.join();\n        } else {\n            System.out.println(\"Doing workLoad myself: \" + this.workLoad);\n            return workLoad;\n        }\n    }\n}\n\npublic class Main {\n    public static void main(String[] args) {\n        ForkJoinPool forkJoinPool = new ForkJoinPool(4);\n        MyRecursiveTask myRecursiveTask = new MyRecursiveTask(123);\n        // int result = forkJoinPool.invoke(myRecursiveTask);\n        ForkJoinTask\u003cInteger\u003e forkJoinTask = forkJoinPool.submit(myRecursiveTask);\n        try {\n            int result = forkJoinTask.get();\n            System.out.println(\"Result :\" + result);\n        } catch (InterruptedException | ExecutionException e) {\n            e.printStackTrace();\n        }\n        System.out.println(\"Main method execution finished\");\n    }\n}\n```\n\n### Output :\n```\nSplitting workLoad : 123\nSplitting workLoad : 61\nSplitting workLoad : 62\nSplitting workLoad : 30\nSplitting workLoad : 31\nSplitting workLoad : 31\nDoing workLoad myself: 15\nDoing workLoad myself: 16\nSplitting workLoad : 31\nDoing workLoad myself: 15\nDoing workLoad myself: 15\nDoing workLoad myself: 16\nDoing workLoad myself: 16\nDoing workLoad myself: 15\nDoing workLoad myself: 15\nResult :123\nMain method execution finished\n```\n\n## RecursiveAction : doesn't return any result, have only fork part\n```java\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.RecursiveAction;\n\nclass MyRecursiveAction extends RecursiveAction {\n    private long workLoad = 0;\n    public MyRecursiveAction(long workLoad) {\n        this.workLoad = workLoad;\n    }\n\n    @Override\n    protected void compute() {\n        // if work is above threshold, break tasks up into smaller tasks\n        if (this.workLoad \u003e 16) {\n            System.out.println(\"Splitting workLoad : \" + this.workLoad);\n            long workload1 = this.workLoad / 2;\n            long workload2 = this.workLoad - workload1;\n            MyRecursiveAction subtask1 = new MyRecursiveAction(workload1);\n            MyRecursiveAction subtask2 = new MyRecursiveAction(workload2);\n            subtask1.fork();\n            subtask2.fork();\n        } else {\n            System.out.println(\"Doing workLoad myself: \" + this.workLoad);\n        }\n    }\n}\n\npublic class Main {\n    public static void main(String[] args) {\n        ForkJoinPool forkJoinPool = new ForkJoinPool(8);\n        MyRecursiveAction myRecursiveAction = new MyRecursiveAction(123);\n        forkJoinPool.invoke(myRecursiveAction);\n        try {\n            Thread.sleep(5000);\n        } catch (InterruptedException exception) {\n            System.out.println(\"Main thread interrupted\");\n        }\n        System.out.println(\"Main method execution finished\");\n    }\n}\n```\n\n## Output :\n```\nSplitting workLoad : 123\nSplitting workLoad : 62\nSplitting workLoad : 61\nSplitting workLoad : 31\nSplitting workLoad : 31\nDoing workLoad myself: 16\nDoing workLoad myself: 15\nSplitting workLoad : 30\nDoing workLoad myself: 15\nDoing workLoad myself: 15\nDoing workLoad myself: 16\nSplitting workLoad : 31\nDoing workLoad myself: 15\nDoing workLoad myself: 15\nDoing workLoad myself: 16\nMain method execution finished\n```\n\n# References :\n1. https://www.pluralsight.com/guides/introduction-to-the-fork-join-framework\n\n2. https://www.youtube.com/watch?v=aiwuJQt7YJU\n\n3. https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/forkjoinpool/JavaForkJoinPoolExample.java\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femahtab%2Ffork-join","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femahtab%2Ffork-join","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femahtab%2Ffork-join/lists"}