Fork-Join means to split the work into fragments and join the results together. You can split the work into components and schedule each component to a thread pool joining the results when all components complete. You can recursively decompose an aggregate structure into identical tasks and join the results when all tasks complete.
By following the divide-and-conquer strategy, problems, such as merge sort of an array, are split into (two or more) smaller sub-problems. If these sub-problems are still too big to be solved directly, they are again recursively split into even smaller sub-problems. Once the sub-problems become small enough, a simple/naive algorithm can be used to solve them. The partial solutions of these sub-problems are then gradually combined into solutions of the original larger problems.
You can visualize the progress of the algorithm as a tree with the original problem as the root, all its direct sub-problems as the nodes right below the root, their sub-problems as the nodes further down and finally with the smallest directly solved problems as the leafs.
Trees are great data structures for parallel processing. The root node typically points to two or more child nodes. These child nodes are roots of their own sub-trees, and these sub-trees are mutually independent. Start a new parallel thread for each of the sub-trees and you are guaranteed the threads will never collide. You get thread-safety by design. This is exactly what fork/join does. Not only does it gradually divide the problem into smaller and smaller sub-problems, but it also allows these sub-problems to be processed concurrently.
As an example, you may try Java 1.7, which comes with a Fork/Join (originally referred to as jsr-166y) framework bundled.