diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -1144,7 +1144,7 @@
     return;
   }
 
-  lld::threadsEnabled = args.hasFlag(OPT_threads, OPT_threads_no, true);
+  lld::enabledThreads = args.hasFlag(OPT_threads, OPT_threads_no, true) ? 0 : 1;
 
   if (args.hasArg(OPT_show_timing))
     config->showTiming = true;
diff --git a/lld/Common/Filesystem.cpp b/lld/Common/Filesystem.cpp
--- a/lld/Common/Filesystem.cpp
+++ b/lld/Common/Filesystem.cpp
@@ -43,7 +43,7 @@
 #if defined(_WIN32)
   sys::fs::remove(path);
 #else
-  if (!threadsEnabled || !sys::fs::exists(path) ||
+  if (enabledThreads == 1 || !sys::fs::exists(path) ||
       !sys::fs::is_regular_file(path))
     return;
 
diff --git a/lld/Common/Threads.cpp b/lld/Common/Threads.cpp
--- a/lld/Common/Threads.cpp
+++ b/lld/Common/Threads.cpp
@@ -8,4 +8,4 @@
 
 #include "lld/Common/Threads.h"
 
-bool lld::threadsEnabled = true;
+int lld::enabledThreads = 0;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -860,7 +860,7 @@
       args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
   errorHandler().vsDiagnostics =
       args.hasArg(OPT_visual_studio_diagnostics_format, false);
-  threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
+  enabledThreads = args::getInteger(args, OPT_threads, 0);
 
   config->allowMultipleDefinition =
       args.hasFlag(OPT_allow_multiple_definition,
diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp
--- a/lld/ELF/ICF.cpp
+++ b/lld/ELF/ICF.cpp
@@ -400,7 +400,7 @@
 void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> fn) {
   // If threading is disabled or the number of sections are
   // too small to use threading, call Fn sequentially.
-  if (!threadsEnabled || sections.size() < 1024) {
+  if (enabledThreads == 1 || sections.size() < 1024) {
     forEachClassRange(0, sections.size(), fn);
     ++cnt;
     return;
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -350,9 +350,8 @@
   Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
   MetaVarName<"<type>">;
 
-defm threads: B<"threads",
-    "Run the linker multi-threaded (default)",
-    "Do not run the linker multi-threaded">;
+defm threads : Eq<"threads", "Number of threads. 0 (default) means all of "
+                             "concurrent threads supported">;
 
 def time_trace: F<"time-trace">, HelpText<"Record time trace">;
 def time_trace_file_eq: J<"time-trace-file=">, HelpText<"Specify time trace output file">;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2747,10 +2747,9 @@
   // of millions for very large executables, so we use multi-threading to
   // speed it up.
   size_t numShards = 32;
-  size_t concurrency = 1;
-  if (threadsEnabled)
-    concurrency = std::min<size_t>(
-        hardware_concurrency().compute_thread_count(), numShards);
+  size_t concurrency = hardware_concurrency().compute_thread_count();
+  if (enabledThreads != 0)
+    concurrency = std::min<size_t>(concurrency, enabledThreads);
 
   // A sharded map to uniquify symbols by name.
   std::vector<DenseMap<CachedHashStringRef, size_t>> map(numShards);
@@ -3194,7 +3193,7 @@
   // Concurrency level. Must be a power of 2 to avoid expensive modulo
   // operations in the following tight loop.
   size_t concurrency = 1;
-  if (threadsEnabled)
+  if (enabledThreads)
     concurrency = std::min<size_t>(
         hardware_concurrency().compute_thread_count(), numShards);
 
diff --git a/lld/include/lld/Common/Threads.h b/lld/include/lld/Common/Threads.h
--- a/lld/include/lld/Common/Threads.h
+++ b/lld/include/lld/Common/Threads.h
@@ -63,10 +63,12 @@
 
 namespace lld {
 
-extern bool threadsEnabled;
+// Number of threads. 0 means all of concurrent threads supported.
+extern int enabledThreads;
 
 template <typename R, class FuncTy> void parallelForEach(R &&range, FuncTy fn) {
-  if (threadsEnabled)
+  // TODO Make llvm::parallel::par support different numbers of threads.
+  if (enabledThreads != 1)
     for_each(llvm::parallel::par, std::begin(range), std::end(range), fn);
   else
     for_each(llvm::parallel::seq, std::begin(range), std::end(range), fn);
@@ -74,14 +76,14 @@
 
 inline void parallelForEachN(size_t begin, size_t end,
                              llvm::function_ref<void(size_t)> fn) {
-  if (threadsEnabled)
+  if (enabledThreads != 1)
     for_each_n(llvm::parallel::par, begin, end, fn);
   else
     for_each_n(llvm::parallel::seq, begin, end, fn);
 }
 
 template <typename R, class FuncTy> void parallelSort(R &&range, FuncTy fn) {
-  if (threadsEnabled)
+  if (enabledThreads != 1)
     sort(llvm::parallel::par, std::begin(range), std::end(range), fn);
   else
     sort(llvm::parallel::seq, std::begin(range), std::end(range), fn);
diff --git a/lld/test/ELF/build-id.s b/lld/test/ELF/build-id.s
--- a/lld/test/ELF/build-id.s
+++ b/lld/test/ELF/build-id.s
@@ -5,26 +5,26 @@
 # RUN: ld.lld --build-id %t -o %t2
 # RUN: llvm-readobj -S %t2 | FileCheck -check-prefix=ALIGN %s
 
-# RUN: ld.lld --build-id %t -o %t2 -threads
+# RUN: ld.lld --build-id %t -o %t2 --threads=0
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=DEFAULT %s
-# RUN: ld.lld --build-id=fast %t -o %t2 -threads
+# RUN: ld.lld --build-id=fast %t -o %t2 --threads=0
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=DEFAULT %s
-# RUN: ld.lld --build-id %t -o %t2 -no-threads
+# RUN: ld.lld --build-id %t -o %t2 --threads=1
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=DEFAULT %s
 
-# RUN: ld.lld --build-id=md5 %t -o %t2 -threads
+# RUN: ld.lld --build-id=md5 %t -o %t2 --threads=0
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=MD5 %s
-# RUN: ld.lld --build-id=md5 %t -o %t2 -no-threads
+# RUN: ld.lld --build-id=md5 %t -o %t2 --threads=1
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=MD5 %s
 
-# RUN: ld.lld --build-id=sha1 %t -o %t2 -threads
+# RUN: ld.lld --build-id=sha1 %t -o %t2 --threads=0
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SHA1 %s
-# RUN: ld.lld --build-id=sha1 %t -o %t2 -no-threads
+# RUN: ld.lld --build-id=sha1 %t -o %t2 --threads=1
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SHA1 %s
 
-# RUN: ld.lld --build-id=tree %t -o %t2 -threads
+# RUN: ld.lld --build-id=tree %t -o %t2 --threads=0
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SHA1 %s
-# RUN: ld.lld --build-id=tree %t -o %t2 -no-threads
+# RUN: ld.lld --build-id=tree %t -o %t2 --threads=1
 # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SHA1 %s
 
 # RUN: ld.lld --build-id=uuid %t -o %t2
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -365,7 +365,7 @@
   config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u);
   errorHandler().verbose = args.hasArg(OPT_verbose);
   LLVM_DEBUG(errorHandler().verbose = true);
-  threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
+  enabledThreads = args::getInteger(args, OPT_threads, 0);
 
   config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
   config->globalBase = args::getInteger(args, OPT_global_base, 1024);
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -64,9 +64,6 @@
 
 def mllvm: S<"mllvm">, HelpText<"Options to pass to LLVM">;
 
-def no_threads: F<"no-threads">,
-  HelpText<"Do not run the linker multi-threaded">;
-
 def no_color_diagnostics: F<"no-color-diagnostics">,
   HelpText<"Do not use colors in diagnostics">;
 
@@ -98,7 +95,8 @@
 
 def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
 
-def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+defm threads : Eq<"threads", "Number of threads. 0 (default) means all of "
+                             "concurrent threads supported">;
 
 def trace: F<"trace">, HelpText<"Print the names of the input files">;