You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2021/10/17 15:55:51 UTC

[lucenenet] 06/08: SWEEP: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.

This is an automated email from the ASF dual-hosted git repository.

nightowl888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucenenet.git

commit 7c357e78adf22207279bc998863b63d714d3442d
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Thu Oct 14 16:00:18 2021 +0700

    SWEEP: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.
---
 .../Analysis/Th/ThaiTokenizer.cs                   | 71 ++++++++++++++---
 .../Analysis/Util/AnalysisSPILoader.cs             |  8 +-
 .../Analysis/Util/BufferedCharFilter.cs            | 43 ++++++++--
 .../Analysis/Icu/Segmentation/ICUTokenizer.cs      | 26 +++++-
 .../Tools/NLPChunkerOp.cs                          |  8 +-
 .../Tools/NLPNERTaggerOp.cs                        |  8 +-
 .../Tools/NLPPOSTaggerOp.cs                        |  8 +-
 .../Tools/NLPSentenceDetectorOp.cs                 |  8 +-
 .../Tools/NLPTokenizerOp.cs                        |  8 +-
 .../Hhmm/BigramDictionary.cs                       |  8 +-
 .../Hhmm/WordDictionary.cs                         |  8 +-
 src/Lucene.Net.Benchmark/ByTask/Benchmark.cs       |  8 +-
 .../ByTask/Feeds/AbstractQueryMaker.cs             |  8 +-
 .../ByTask/Feeds/ContentItemsSource.cs             | 15 +++-
 .../ByTask/Feeds/DirContentSource.cs               | 15 +++-
 .../ByTask/Feeds/EnwikiContentSource.cs            | 63 +++++++++++----
 .../ByTask/Feeds/LineDocSource.cs                  |  8 +-
 .../ByTask/Feeds/LongToEnglishContentSource.cs     | 17 +++-
 .../ByTask/Feeds/LongToEnglishQueryMaker.cs        | 15 +++-
 .../ByTask/Feeds/ReutersContentSource.cs           | 15 +++-
 .../ByTask/Feeds/SingleDocSource.cs                | 18 ++++-
 .../ByTask/Feeds/TrecContentSource.cs              | 15 +++-
 src/Lucene.Net.Benchmark/ByTask/PerfRunData.cs     | 57 ++++++++++++--
 src/Lucene.Net.Benchmark/ByTask/Stats/Points.cs    | 22 +++++-
 .../ByTask/Tasks/NearRealtimeReaderTask.cs         |  1 +
 .../ByTask/Tasks/TaskSequence.cs                   |  1 +
 src/Lucene.Net.Benchmark/ByTask/Tasks/WaitTask.cs  |  3 +-
 .../ByTask/Tasks/WriteLineDocTask.cs               | 15 +++-
 .../Memory/DirectDocValuesProducer.cs              | 36 +++++++--
 .../Memory/MemoryDocValuesProducer.cs              | 36 +++++++--
 .../SimpleText/SimpleTextFieldsReader.cs           |  8 +-
 src/Lucene.Net.Facet/FacetsConfig.cs               | 36 +++++++--
 .../Taxonomy/CachedOrdinalsReader.cs               | 15 +++-
 .../Taxonomy/Directory/DirectoryTaxonomyWriter.cs  | 92 +++++++++++++++++++---
 src/Lucene.Net.Facet/Taxonomy/TaxonomyReader.cs    |  8 +-
 .../WriterCache/Cl2oTaxonomyWriterCache.cs         |  8 +-
 .../Taxonomy/WriterCache/LruTaxonomyWriterCache.cs | 36 +++++++--
 .../Taxonomy/WriterCache/NameIntCacheLRU.cs        |  8 +-
 .../AbstractFirstPassGroupingCollector.cs          | 15 +++-
 src/Lucene.Net.Misc/Document/LazyDocument.cs       | 15 +++-
 .../Surround/Query/BasicQueryFactory.cs            |  8 +-
 .../Xml/Builders/CachedFilterBuilder.cs            |  8 +-
 .../Xml/Builders/UserInputQueryBuilder.cs          |  8 +-
 src/Lucene.Net.Replicator/LocalReplicator.cs       | 50 ++++++++++--
 src/Lucene.Net.Replicator/ReplicationClient.cs     | 14 +++-
 src/Lucene.Net.Suggest/Spell/SpellChecker.cs       | 45 +++++++++--
 .../Suggest/Analyzing/AnalyzingInfixSuggester.cs   |  8 +-
 .../Suggest/Fst/FSTCompletionLookup.cs             | 15 +++-
 src/Lucene.Net.Suggest/Suggest/Tst/TSTLookup.cs    | 15 +++-
 .../Index/BaseDocValuesFormatTestCase.cs           |  1 +
 .../Index/ThreadedIndexingAndSearchingTestCase.cs  |  1 +
 .../Analysis/Th/TestThaiAnalyzer.cs                |  1 +
 .../Analysis/Icu/Segmentation/TestICUTokenizer.cs  |  1 +
 .../ByTask/Tasks/CountingSearchTestTask.cs         |  8 +-
 src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs     | 17 ++--
 .../Taxonomy/TestSearcherTaxonomyManager.cs        |  1 +
 .../Taxonomy/TestTaxonomyCombined.cs               |  2 +
 .../IndexAndTaxonomyReplicationClientTest.cs       |  1 +
 .../IndexReplicationClientTest.cs                  |  1 +
 .../LocalReplicatorTest.cs                         |  1 +
 .../Spell/TestSpellChecker.cs                      |  1 +
 .../Analyzing/AnalyzingInfixSuggesterTest.cs       |  1 +
 src/Lucene.Net.Tests/Index/TestAddIndexes.cs       | 22 +++++-
 src/Lucene.Net.Tests/Index/TestBagOfPositions.cs   |  1 +
 src/Lucene.Net.Tests/Index/TestBagOfPostings.cs    |  1 +
 .../Index/TestConcurrentMergeScheduler.cs          |  1 +
 src/Lucene.Net.Tests/Index/TestDeletionPolicy.cs   |  1 +
 src/Lucene.Net.Tests/Index/TestDirectoryReader.cs  |  1 +
 .../Index/TestDirectoryReaderReopen.cs             | 35 ++++++--
 .../Index/TestDocumentsWriterStallControl.cs       |  4 +-
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs      | 33 +++++++-
 .../Index/TestIndexWriterExceptions.cs             |  8 +-
 .../Index/TestIndexWriterMerging.cs                |  8 +-
 .../Index/TestIndexWriterNRTIsCurrent.cs           |  1 +
 .../Index/TestIndexWriterOnJRECrash.cs             |  1 +
 .../Index/TestIndexWriterReader.cs                 |  8 +-
 .../Index/TestNRTReaderWithThreads.cs              |  1 +
 src/Lucene.Net.Tests/Index/TestNeverDelete.cs      |  1 +
 src/Lucene.Net.Tests/Index/TestPayloads.cs         | 22 +++++-
 .../Index/TestSnapshotDeletionPolicy.cs            |  1 +
 src/Lucene.Net.Tests/Index/TestStressIndexing2.cs  | 22 +++++-
 src/Lucene.Net.Tests/Index/TestStressNRT.cs        | 29 ++++++-
 src/Lucene.Net.Tests/Index/TestTransactions.cs     | 15 +++-
 .../Search/TestControlledRealTimeReopenThread.cs   |  8 +-
 .../Search/TestMultiThreadTermVectors.cs           |  1 +
 src/Lucene.Net.Tests/Search/TestSearcherManager.cs | 15 +++-
 .../Search/TestTimeLimitingCollector.cs            |  8 +-
 src/Lucene.Net.Tests/Store/TestLockFactory.cs      |  1 +
 src/Lucene.Net.Tests/TestWorstCaseTestBehavior.cs  |  1 +
 src/Lucene.Net.Tests/Util/TestSetOnce.cs           |  1 +
 90 files changed, 1087 insertions(+), 185 deletions(-)

diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs b/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs
index e3e7323..3bc1a83 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs
@@ -1,9 +1,10 @@
-// Lucene version compatibility level 4.8.1
+// Lucene version compatibility level 4.8.1
 #if FEATURE_BREAKITERATOR
 using ICU4N.Text;
 using J2N;
 using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Analysis.Util;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -54,14 +55,28 @@ namespace Lucene.Net.Analysis.Th
 
         private static BreakIterator LoadProto()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 return BreakIterator.GetWordInstance(new CultureInfo("th"));
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private static BreakIterator LoadSentenceProto()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 return BreakIterator.GetSentenceInstance(CultureInfo.InvariantCulture);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private readonly ThaiWordBreaker wordBreaker;
@@ -87,45 +102,79 @@ namespace Lucene.Net.Analysis.Th
         {
             // LUCENENET specific - DBBI_AVAILABLE removed because ICU always has a dictionary-based BreakIterator
 
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 wordBreaker = new ThaiWordBreaker((BreakIterator)proto.Clone());
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
             termAtt = AddAttribute<ICharTermAttribute>();
             offsetAtt = AddAttribute<IOffsetAttribute>();
         }
 
         private static BreakIterator CreateSentenceClone()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 return (BreakIterator)sentenceProto.Clone();
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public override void Reset()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 base.Reset();
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public override State CaptureState()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 return base.CaptureState();
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         protected override void SetNextSentence(int sentenceStart, int sentenceEnd)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 this.sentenceStart = sentenceStart;
                 this.sentenceEnd = sentenceEnd;
                 wrapper.SetText(m_buffer, sentenceStart, sentenceEnd - sentenceStart);
                 wordBreaker.SetText(new string(wrapper.Text, wrapper.Start, wrapper.Length));
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         protected override bool IncrementWord()
         {
             int start, end;
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 start = wordBreaker.Current;
                 if (start == BreakIterator.Done)
@@ -151,6 +200,10 @@ namespace Lucene.Net.Analysis.Th
                 offsetAtt.SetOffset(CorrectOffset(m_offset + sentenceStart + start), CorrectOffset(m_offset + sentenceStart + end));
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
     }
 
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Util/AnalysisSPILoader.cs b/src/Lucene.Net.Analysis.Common/Analysis/Util/AnalysisSPILoader.cs
index 3d4224b..5c27659 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Util/AnalysisSPILoader.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Util/AnalysisSPILoader.cs
@@ -1,6 +1,7 @@
 // Lucene version compatibility level 4.8.1
 using J2N.Collections.Generic.Extensions;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -60,7 +61,8 @@ namespace Lucene.Net.Analysis.Util
         /// </summary>
         public void Reload()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 IDictionary<string, Type> services = new JCG.LinkedDictionary<string, Type>(this.services);
                 SPIClassIterator<S> loader = SPIClassIterator<S>.Get();
@@ -98,6 +100,10 @@ namespace Lucene.Net.Analysis.Util
                 }
                 this.services = services.AsReadOnly();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public S NewInstance(string name, IDictionary<string, string> args)
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs b/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
index 4d6a86e..bceb42c 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
@@ -3,6 +3,7 @@
 // https://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/
 
 using Lucene.Net.Analysis.CharFilters;
+using Lucene.Net.Support.Threading;
 using System;
 using System.IO;
 using System.Text;
@@ -119,7 +120,8 @@ namespace Lucene.Net.Analysis.Util
 #if FEATURE_TEXTWRITER_CLOSE
                 this.isDisposing = true;
 #endif
-                lock (m_lock)
+                UninterruptableMonitor.Enter(m_lock);
+                try
                 {
                     if (!IsClosed)
                     {
@@ -128,6 +130,10 @@ namespace Lucene.Net.Analysis.Util
                         buf = null;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_lock);
+                }
 #if FEATURE_TEXTWRITER_CLOSE
                 this.isDisposing = false;
 #endif
@@ -225,12 +231,17 @@ namespace Lucene.Net.Analysis.Util
             {
                 throw new ArgumentOutOfRangeException(nameof(markLimit), "Read-ahead limit < 0");
             }
-            lock (m_lock)
+            UninterruptableMonitor.Enter(m_lock);
+            try
             {
                 EnsureOpen();
                 this.markLimit = markLimit;
                 mark = pos;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_lock);
+            }
         }
 
         /// <summary>
@@ -253,7 +264,8 @@ namespace Lucene.Net.Analysis.Util
         /// <exception cref="IOException">If this reader is disposed or some other I/O error occurs.</exception>
         public override int Read()
         {
-            lock (m_lock)
+            UninterruptableMonitor.Enter(m_lock);
+            try
             {
                 EnsureOpen();
                 /* Are there buffered characters available? */
@@ -263,6 +275,10 @@ namespace Lucene.Net.Analysis.Util
                 }
                 return -1;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_lock);
+            }
         }
 
         /// <summary>
@@ -483,13 +499,18 @@ namespace Lucene.Net.Analysis.Util
         {
             get
             {
-                lock (m_lock)
+                UninterruptableMonitor.Enter(m_lock);
+                try
                 {
                     EnsureOpen();
                     // LUCENENET specific: only CharFilter derived types support IsReady
                     var charFilter = @in as CharFilter;
                     return ((end - pos) > 0) || (charFilter != null && charFilter.IsReady);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_lock);
+                }
             }
         }
 
@@ -503,7 +524,8 @@ namespace Lucene.Net.Analysis.Util
         /// <seealso cref="IsMarkSupported"/>
         public override void Reset()
         {
-            lock (m_lock)
+            UninterruptableMonitor.Enter(m_lock);
+            try
             {
                 EnsureOpen();
                 if (mark < 0)
@@ -513,6 +535,10 @@ namespace Lucene.Net.Analysis.Util
                 }
                 pos = mark;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_lock);
+            }
         }
 
         /// <summary>
@@ -534,7 +560,8 @@ namespace Lucene.Net.Analysis.Util
             {
                 throw new ArgumentOutOfRangeException(nameof(amount), "skip value is negative");
             }
-            lock (m_lock)
+            UninterruptableMonitor.Enter(m_lock);
+            try
             {
                 EnsureOpen();
                 if (amount < 1)
@@ -566,6 +593,10 @@ namespace Lucene.Net.Analysis.Util
                 }
                 return amount;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_lock);
+            }
         }
 
 #region LUCENENET Specific Methods
diff --git a/src/Lucene.Net.Analysis.ICU/Analysis/Icu/Segmentation/ICUTokenizer.cs b/src/Lucene.Net.Analysis.ICU/Analysis/Icu/Segmentation/ICUTokenizer.cs
index e9d207a..ab79760 100644
--- a/src/Lucene.Net.Analysis.ICU/Analysis/Icu/Segmentation/ICUTokenizer.cs
+++ b/src/Lucene.Net.Analysis.ICU/Analysis/Icu/Segmentation/ICUTokenizer.cs
@@ -5,6 +5,7 @@ using Lucene.Net.Analysis.Icu.TokenAttributes;
 using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Diagnostics;
 using System.IO;
@@ -111,7 +112,8 @@ namespace Lucene.Net.Analysis.Icu.Segmentation
 
         public override bool IncrementToken()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 ClearAttributes();
                 if (length == 0)
@@ -124,14 +126,25 @@ namespace Lucene.Net.Analysis.Icu.Segmentation
                 }
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
 
         public override void Reset()
         {
             base.Reset();
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 breaker.SetText(buffer, 0, 0);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
             length = usableLength = offset = 0;
         }
 
@@ -193,8 +206,15 @@ namespace Lucene.Net.Analysis.Icu.Segmentation
                                 */
             }
 
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
+            {
                 breaker.SetText(buffer, 0, Math.Max(0, usableLength));
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         // TODO: refactor to a shared readFully somewhere
diff --git a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPChunkerOp.cs b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPChunkerOp.cs
index de53e3b..8f870b7 100644
--- a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPChunkerOp.cs
+++ b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPChunkerOp.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 8.2.0
+using Lucene.Net.Support.Threading;
 using opennlp.tools.chunker;
 
 
@@ -36,13 +37,18 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
 
         public virtual string[] GetChunks(string[] words, string[] tags, double[] probs)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 string[] chunks = chunker.chunk(words, tags);
                 if (probs != null)
                     chunker.probs(probs);
                 return chunks;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPNERTaggerOp.cs b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPNERTaggerOp.cs
index 614ae52..733bcd0 100644
--- a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPNERTaggerOp.cs
+++ b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPNERTaggerOp.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 8.2.0
+using Lucene.Net.Support.Threading;
 using opennlp.tools.namefind;
 using opennlp.tools.util;
 
@@ -53,10 +54,15 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
 
         public virtual void Reset()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 nameFinder.clearAdaptiveData();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPPOSTaggerOp.cs b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPPOSTaggerOp.cs
index 2f1e090..cce97eb 100644
--- a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPPOSTaggerOp.cs
+++ b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPPOSTaggerOp.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 8.2.0
+using Lucene.Net.Support.Threading;
 using opennlp.tools.postag;
 
 namespace Lucene.Net.Analysis.OpenNlp.Tools
@@ -35,10 +36,15 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
 
         public virtual string[] GetPOSTags(string[] words)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return tagger.tag(words);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPSentenceDetectorOp.cs b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPSentenceDetectorOp.cs
index 70c69ac..41ddb17 100644
--- a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPSentenceDetectorOp.cs
+++ b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPSentenceDetectorOp.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 8.2.0
+using Lucene.Net.Support.Threading;
 using opennlp.tools.sentdetect;
 using opennlp.tools.util;
 
@@ -41,7 +42,8 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
 
         public virtual Span[] SplitSentences(string line)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (sentenceSplitter != null)
                 {
@@ -54,6 +56,10 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
                     return shorty;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPTokenizerOp.cs b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPTokenizerOp.cs
index 81df103..98ca819 100644
--- a/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPTokenizerOp.cs
+++ b/src/Lucene.Net.Analysis.OpenNLP/Tools/NLPTokenizerOp.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 8.2.0
+using Lucene.Net.Support.Threading;
 using opennlp.tools.tokenize;
 using opennlp.tools.util;
 
@@ -41,7 +42,8 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
 
         public virtual Span[] GetTerms(string sentence)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (tokenizer == null)
                 {
@@ -51,6 +53,10 @@ namespace Lucene.Net.Analysis.OpenNlp.Tools
                 }
                 return tokenizer.tokenizePos(sentence);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Analysis.SmartCn/Hhmm/BigramDictionary.cs b/src/Lucene.Net.Analysis.SmartCn/Hhmm/BigramDictionary.cs
index 2925dd6..c220ad3 100644
--- a/src/Lucene.Net.Analysis.SmartCn/Hhmm/BigramDictionary.cs
+++ b/src/Lucene.Net.Analysis.SmartCn/Hhmm/BigramDictionary.cs
@@ -1,6 +1,7 @@
 // lucene version compatibility level: 4.8.1
 using J2N;
 using J2N.IO;
+using Lucene.Net.Support.Threading;
 using System;
 using System.IO;
 using System.Text;
@@ -58,7 +59,8 @@ namespace Lucene.Net.Analysis.Cn.Smart.Hhmm
 
         public static BigramDictionary GetInstance()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (singleInstance == null)
                 {
@@ -81,6 +83,10 @@ namespace Lucene.Net.Analysis.Cn.Smart.Hhmm
                 }
                 return singleInstance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private bool LoadFromObj(FileInfo serialObj)
diff --git a/src/Lucene.Net.Analysis.SmartCn/Hhmm/WordDictionary.cs b/src/Lucene.Net.Analysis.SmartCn/Hhmm/WordDictionary.cs
index 906e6b3..eee9188 100644
--- a/src/Lucene.Net.Analysis.SmartCn/Hhmm/WordDictionary.cs
+++ b/src/Lucene.Net.Analysis.SmartCn/Hhmm/WordDictionary.cs
@@ -1,6 +1,7 @@
 // lucene version compatibility level: 4.8.1
 using J2N;
 using J2N.IO;
+using Lucene.Net.Support.Threading;
 using System;
 using System.IO;
 using System.Text;
@@ -76,7 +77,8 @@ namespace Lucene.Net.Analysis.Cn.Smart.Hhmm
         /// <returns>singleton</returns>
         public static WordDictionary GetInstance()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (singleInstance == null)
                 {
@@ -99,6 +101,10 @@ namespace Lucene.Net.Analysis.Cn.Smart.Hhmm
                 }
                 return singleInstance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Benchmark/ByTask/Benchmark.cs b/src/Lucene.Net.Benchmark/ByTask/Benchmark.cs
index dc3f504..6b0b7a9 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Benchmark.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Benchmark.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Benchmarks.ByTask.Utils;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.IO;
@@ -78,7 +79,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// </summary>
         public virtual void Execute()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (executed)
                 {
@@ -88,6 +90,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                 runData.SetStartTimeMillis();
                 algorithm.Execute();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/AbstractQueryMaker.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/AbstractQueryMaker.cs
index fb6a2bf..a9d5f50 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/AbstractQueryMaker.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/AbstractQueryMaker.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Benchmarks.ByTask.Utils;
 using Lucene.Net.Search;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Text;
 
@@ -68,12 +69,17 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
         // return next qnum
         protected virtual int NextQnum()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 int res = m_qnum;
                 m_qnum = (m_qnum + 1) % m_queries.Length;
                 return res;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <seealso cref="IQueryMaker.MakeQuery(int)"/>
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/ContentItemsSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/ContentItemsSource.cs
index be45d38..2029837 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/ContentItemsSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/ContentItemsSource.cs
@@ -1,5 +1,6 @@
 using J2N.Text;
 using Lucene.Net.Benchmarks.ByTask.Utils;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -71,21 +72,31 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
         /// <summary>update count of bytes generated by this source</summary>
         protected void AddBytes(long numBytes)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 bytesCount += numBytes;
                 totalBytesCount += numBytes;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>update count of items generated by this source</summary>
         protected void AddItem()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 ++itemCount;
                 ++totalItemCount;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/DirContentSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/DirContentSource.cs
index 10e0248..b364796 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/DirContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/DirContentSource.cs
@@ -1,6 +1,7 @@
 using J2N.Text;
 using Lucene.Net.Benchmarks.ByTask.Utils;
 using Lucene.Net.Support.IO;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -182,7 +183,8 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
         {
             FileInfo f = null;
             string name = null;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!inputFiles.MoveNext())
                 {
@@ -198,6 +200,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 // System.err.println(f);
                 name = f.GetCanonicalPath() + "_" + iteration;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             string line = null;
             string dateStr;
@@ -230,12 +236,17 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
 
         public override void ResetInputs()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 base.ResetInputs();
                 inputFiles = new Enumerator(dataDir);
                 iteration = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void SetConfig(Config config)
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
index 1e06701..633bf46 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
@@ -2,6 +2,7 @@
 
 using J2N.Threading;
 using Lucene.Net.Benchmarks.ByTask.Utils;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using Sax;
 using Sax.Helpers;
@@ -73,13 +74,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                     t.Start();
                 }
                 string[] result;
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     while (tuple == null && nmde == null && !threadDone && !stopped)
                     {
                         try
                         {
-                            Monitor.Wait(this);
+                            UninterruptableMonitor.Wait(this);
                         }
                         catch (Exception ie) when (ie.IsInterruptedException())
                         {
@@ -106,6 +108,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                     // benchmark to stop the current alg:
                     throw new NoMoreDataException();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             internal string Time(string original)
@@ -144,13 +150,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                             tmpTuple[DATE] = time.Replace('\t', ' ');
                             tmpTuple[BODY] = Regex.Replace(body, "[\t\n]", " ");
                             tmpTuple[ID] = id;
-                            lock (this)
+                            UninterruptableMonitor.Enter(this);
+                            try
                             {
                                 while (tuple != null && !stopped)
                                 {
                                     try
                                     {
-                                        Monitor.Wait(this); //wait();
+                                        UninterruptableMonitor.Wait(this); //wait();
                                     }
                                     catch (System.Threading.ThreadInterruptedException ie)
                                     {
@@ -158,7 +165,11 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                                     }
                                 }
                                 tuple = tmpTuple;
-                                Monitor.Pulse(this); //notify();
+                                UninterruptableMonitor.Pulse(this); //notify();
+                            }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(this);
                             }
                         }
                         break;
@@ -211,7 +222,8 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                             }
                             catch (Exception ioe) when (ioe.IsIOException())
                             {
-                                lock (outerInstance)
+                                UninterruptableMonitor.Enter(outerInstance);
+                                try
                                 {
                                     if (localFileIS != outerInstance.@is)
                                     {
@@ -221,14 +233,19 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                                         // Exception is real
                                         throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
                                 }
+                                finally
+                                {
+                                    UninterruptableMonitor.Exit(outerInstance);
+                                }
                             }
                         }
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             if (stopped || !outerInstance.m_forever)
                             {
                                 nmde = new NoMoreDataException();
-                                Monitor.Pulse(this); //notify();
+                                UninterruptableMonitor.Pulse(this); //notify();
                                 return;
                             }
                             else if (localFileIS == outerInstance.@is)
@@ -237,6 +254,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                                 outerInstance.@is = outerInstance.OpenInputStream();
                             }
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
                 catch (SAXException sae)
@@ -249,10 +270,15 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 }
                 finally
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         threadDone = true;
-                        Monitor.Pulse(this); //Notify();
+                        UninterruptableMonitor.Pulse(this); //Notify();
+                    }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
                     }
                 }
             }
@@ -284,15 +310,20 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
 
             internal void Stop()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     stopped = true;
                     if (tuple != null)
                     {
                         tuple = null;
-                        Monitor.Pulse(this); //Notify();
+                        UninterruptableMonitor.Pulse(this); //Notify();
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -342,16 +373,20 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     parser.Stop();
                     if (@is != null)
                     {
-                        Thread.Sleep(1); // LUCENENET: Allow parser to stop before Dispose() is called
                         @is.Dispose();
                         @is = null;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/LineDocSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/LineDocSource.cs
index 17a821e..505fc85 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/LineDocSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/LineDocSource.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Benchmarks.ByTask.Tasks;
 using Lucene.Net.Benchmarks.ByTask.Utils;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -85,7 +86,8 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
             int myID;
 
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 line = reader.ReadLine();
                 if (line == null)
@@ -109,6 +111,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 // increment IDS only once...
                 myID = readCount++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             // The date String was written in the format of DateTools.dateToString.
             docData.Clear();
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishContentSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishContentSource.cs
index 7b4ab5f..7c05a68 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishContentSource.cs
@@ -1,4 +1,5 @@
-using Lucene.Net.Util;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
 using System;
 using System.Globalization;
 
@@ -38,12 +39,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
         //                                                                     RuleBasedNumberFormat.SPELLOUT);
         public override DocData GetNextDocData(DocData docData)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 docData.Clear();
                 // store the current counter to avoid synchronization later on
                 long curCounter;
-                lock (this)
+                UninterruptableMonitor.Enter(this); // LUCENENET TODO: Since the whole method is synchronized, do we need this?
+                try
                 {
                     curCounter = counter;
                     if (counter == long.MaxValue)
@@ -55,6 +58,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                         ++counter;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 docData.Body = curCounter.ToWords(); //rnbf.format(curCounter);
                 docData.Name = "doc_" + curCounter.ToString(CultureInfo.InvariantCulture);
@@ -62,6 +69,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 docData.SetDate(new DateTime());
                 return docData;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void ResetInputs()
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishQueryMaker.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishQueryMaker.cs
index 78580db..37ea280 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishQueryMaker.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/LongToEnglishQueryMaker.cs
@@ -5,6 +5,7 @@ using Lucene.Net.Benchmarks.ByTask.Utils;
 using Lucene.Net.QueryParsers.Classic;
 using Lucene.Net.Search;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 
@@ -47,16 +48,22 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
 
         public virtual Query MakeQuery()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 //return parser.Parse("" + rnbf.format(GetNextCounter()) + "");
                 return m_parser.Parse(GetNextCounter().ToWords());
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private long GetNextCounter()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (counter == long.MaxValue)
                 {
@@ -64,6 +71,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 }
                 return counter++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void SetConfig(Config config)
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/ReutersContentSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/ReutersContentSource.cs
index 51815d9..13a78bb 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/ReutersContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/ReutersContentSource.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Benchmarks.ByTask.Utils;
 using Lucene.Net.Support.IO;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -82,7 +83,8 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
         {
             FileInfo f = null;
             string name = null;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (nextFile >= inputFiles.Count)
                 {
@@ -97,6 +99,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 f = inputFiles[nextFile++];
                 name = f.GetCanonicalPath() + "_" + iteration;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             using TextReader reader = new StreamReader(new FileStream(f.FullName, FileMode.Open, FileAccess.Read), Encoding.UTF8);
             // First line is the date, 3rd is the title, rest is body
@@ -127,12 +133,17 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
 
         public override void ResetInputs()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 base.ResetInputs();
                 nextFile = 0;
                 iteration = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/SingleDocSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/SingleDocSource.cs
index 6fed314..6636af6 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/SingleDocSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/SingleDocSource.cs
@@ -1,4 +1,6 @@
-namespace Lucene.Net.Benchmarks.ByTask.Feeds
+using Lucene.Net.Support.Threading;
+
+namespace Lucene.Net.Benchmarks.ByTask.Feeds
 {
     /*
      * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -43,7 +45,8 @@
         // return a new docid
         private int NewDocID()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (docID > 0 && !m_forever)
                 {
@@ -51,6 +54,10 @@
                 }
                 return docID++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void Dispose(bool disposing) { }
@@ -67,11 +74,16 @@
 
         public override void ResetInputs()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 base.ResetInputs();
                 docID = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/TrecContentSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/TrecContentSource.cs
index ec50045..a12d658 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/TrecContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/TrecContentSource.cs
@@ -1,5 +1,6 @@
 using J2N.Text;
 using Lucene.Net.Benchmarks.ByTask.Utils;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -261,7 +262,8 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
 
             // protect reading from the TREC files by multiple threads. The rest of the
             // method, i.e., parsing the content and returning the DocData can run unprotected.
-            lock (@lock)
+            UninterruptableMonitor.Enter(@lock);
+            try
             {
                 if (reader == null)
                 {
@@ -291,6 +293,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 docBuf.Length = 0;
                 Read(docBuf, TERMINATING_DOC, false, true);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(@lock);
+            }
 
             // count char length of text to be parsed (may be larger than the resulted plain doc body text).
             AddBytes(docBuf.Length);
@@ -305,13 +311,18 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
 
         public override void ResetInputs()
         {
-            lock (@lock)
+            UninterruptableMonitor.Enter(@lock);
+            try
             {
                 base.ResetInputs();
                 DoClose();
                 nextFile = 0;
                 iteration = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(@lock);
+            }
         }
 
         public override void SetConfig(Config config)
diff --git a/src/Lucene.Net.Benchmark/ByTask/PerfRunData.cs b/src/Lucene.Net.Benchmark/ByTask/PerfRunData.cs
index 670e72b..2b6c50a 100644
--- a/src/Lucene.Net.Benchmark/ByTask/PerfRunData.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/PerfRunData.cs
@@ -7,6 +7,7 @@ using Lucene.Net.Facet.Taxonomy;
 using Lucene.Net.Index;
 using Lucene.Net.Search;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -209,11 +210,16 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// </summary>
         public virtual object GetPerfObject(string key)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 perfObjects.TryGetValue(key, out object result);
                 return result;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -223,10 +229,15 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// </summary>
         public virtual void SetPerfObject(string key, object obj)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 perfObjects[key] = obj;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual long SetStartTimeMillis()
@@ -268,7 +279,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// <param name="taxoReader">The taxonomy reader to set.</param>
         public virtual void SetTaxonomyReader(TaxonomyReader taxoReader)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (taxoReader == this.taxonomyReader)
                 {
@@ -285,6 +297,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                 }
                 this.taxonomyReader = taxoReader;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -294,7 +310,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// </summary>
         public virtual TaxonomyReader GetTaxonomyReader()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (taxonomyReader != null)
                 {
@@ -302,6 +319,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                 }
                 return taxonomyReader;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -320,7 +341,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// </summary>
         public virtual DirectoryReader GetIndexReader()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (indexReader != null)
                 {
@@ -328,6 +350,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                 }
                 return indexReader;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -338,7 +364,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// <returns></returns>
         public virtual IndexSearcher GetIndexSearcher()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (indexReader != null)
                 {
@@ -346,6 +373,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                 }
                 return indexSearcher;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -357,7 +388,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// <param name="indexReader">The indexReader to set.</param>
         public virtual void SetIndexReader(DirectoryReader indexReader)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (indexReader == this.indexReader)
                 {
@@ -382,6 +414,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                     indexSearcher = null;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -441,7 +477,8 @@ namespace Lucene.Net.Benchmarks.ByTask
         /// </summary>
         public virtual IQueryMaker GetQueryMaker(ReadTask readTask)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // mapping the query maker by task class allows extending/adding new search/read tasks
                 // without needing to modify this class.
@@ -462,6 +499,10 @@ namespace Lucene.Net.Benchmarks.ByTask
                 }
                 return qm;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual IDictionary<string, AnalyzerFactory> AnalyzerFactories => analyzerFactories;
diff --git a/src/Lucene.Net.Benchmark/ByTask/Stats/Points.cs b/src/Lucene.Net.Benchmark/ByTask/Stats/Points.cs
index b12985f..ec76aa7 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Stats/Points.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Stats/Points.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Benchmarks.ByTask.Tasks;
 using Lucene.Net.Benchmarks.ByTask.Utils;
+using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
 
 namespace Lucene.Net.Benchmarks.ByTask.Stats
@@ -59,13 +60,18 @@ namespace Lucene.Net.Benchmarks.ByTask.Stats
         /// <returns></returns>
         public virtual TaskStats MarkTaskStart(PerfTask task, int round)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 TaskStats stats = new TaskStats(task, NextTaskRunNum(), round);
                 this.currentStats = stats;
                 points.Add(stats);
                 return stats;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual TaskStats CurrentStats => currentStats;
@@ -73,10 +79,15 @@ namespace Lucene.Net.Benchmarks.ByTask.Stats
         // return next task num
         private int NextTaskRunNum()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return nextTaskRunNum++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -84,13 +95,18 @@ namespace Lucene.Net.Benchmarks.ByTask.Stats
         /// </summary>
         public virtual void MarkTaskEnd(TaskStats stats, int count)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 int numParallelTasks = nextTaskRunNum - 1 - stats.TaskRunNum;
                 // note: if the stats were cleared, might be that this stats object is 
                 // no longer in points, but this is just ok.
                 stats.MarkEnd(numParallelTasks, count);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Benchmark/ByTask/Tasks/NearRealtimeReaderTask.cs b/src/Lucene.Net.Benchmark/ByTask/Tasks/NearRealtimeReaderTask.cs
index fc0c264..4df03e7 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Tasks/NearRealtimeReaderTask.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Tasks/NearRealtimeReaderTask.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Globalization;
diff --git a/src/Lucene.Net.Benchmark/ByTask/Tasks/TaskSequence.cs b/src/Lucene.Net.Benchmark/ByTask/Tasks/TaskSequence.cs
index f911a29..43bd6f9 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Tasks/TaskSequence.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Tasks/TaskSequence.cs
@@ -1,6 +1,7 @@
 using J2N.Threading;
 using Lucene.Net.Benchmarks.ByTask.Feeds;
 using Lucene.Net.Benchmarks.ByTask.Stats;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
diff --git a/src/Lucene.Net.Benchmark/ByTask/Tasks/WaitTask.cs b/src/Lucene.Net.Benchmark/ByTask/Tasks/WaitTask.cs
index 90600d0..a00a383 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Tasks/WaitTask.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Tasks/WaitTask.cs
@@ -1,4 +1,5 @@
-using System;
+using Lucene.Net.Support.Threading;
+using System;
 using System.Globalization;
 using System.Threading;
 
diff --git a/src/Lucene.Net.Benchmark/ByTask/Tasks/WriteLineDocTask.cs b/src/Lucene.Net.Benchmark/ByTask/Tasks/WriteLineDocTask.cs
index b4f4209..53cfa89 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Tasks/WriteLineDocTask.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Tasks/WriteLineDocTask.cs
@@ -3,6 +3,7 @@ using Lucene.Net.Benchmarks.ByTask.Feeds;
 using Lucene.Net.Benchmarks.ByTask.Utils;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -160,10 +161,15 @@ namespace Lucene.Net.Benchmarks.ByTask.Tasks
             {
                 sb.Append(SEP).Append(f);
             }
-            lock (lineFileLock) // LUCENENET specific - lock to ensure writes don't collide for this instance
+            UninterruptableMonitor.Enter(lineFileLock);
+            try // LUCENENET specific - lock to ensure writes don't collide for this instance
             {
                 @out.WriteLine(sb.ToString());
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(lineFileLock);
+            }
         }
 
         protected override string GetLogMessage(int recsCount)
@@ -202,10 +208,15 @@ namespace Lucene.Net.Benchmarks.ByTask.Tasks
             {
                 sb.Length--; // remove redundant last separator
                 // lineFileOut is a PrintWriter, which synchronizes internally in println.
-                lock (lineFileLock) // LUCENENET specific - lock to ensure writes don't collide for this instance
+                UninterruptableMonitor.Enter(lineFileLock); // LUCENENET specific - lock to ensure writes don't collide for this instance
+                try
                 {
                     LineFileOut(doc).WriteLine(sb.ToString());
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(lineFileLock);
+                }
             }
 
             return 1;
diff --git a/src/Lucene.Net.Codecs/Memory/DirectDocValuesProducer.cs b/src/Lucene.Net.Codecs/Memory/DirectDocValuesProducer.cs
index 9c97c64..06f6305 100644
--- a/src/Lucene.Net.Codecs/Memory/DirectDocValuesProducer.cs
+++ b/src/Lucene.Net.Codecs/Memory/DirectDocValuesProducer.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -211,7 +212,8 @@ namespace Lucene.Net.Codecs.Memory
 
         public override NumericDocValues GetNumeric(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!numericInstances.TryGetValue(field.Number, out NumericDocValues instance))
                 {
@@ -221,6 +223,10 @@ namespace Lucene.Net.Codecs.Memory
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private NumericDocValues LoadNumeric(NumericEntry entry)
@@ -337,7 +343,8 @@ namespace Lucene.Net.Codecs.Memory
 
         public override BinaryDocValues GetBinary(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!binaryInstances.TryGetValue(field.Number, out BinaryDocValues instance))
                 {
@@ -347,6 +354,10 @@ namespace Lucene.Net.Codecs.Memory
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private BinaryDocValues LoadBinary(BinaryEntry entry)
@@ -389,7 +400,8 @@ namespace Lucene.Net.Codecs.Memory
 
         public override SortedDocValues GetSorted(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!sortedInstances.TryGetValue(field.Number, out SortedDocValues instance))
                 {
@@ -399,6 +411,10 @@ namespace Lucene.Net.Codecs.Memory
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private SortedDocValues LoadSorted(FieldInfo field)
@@ -443,7 +459,8 @@ namespace Lucene.Net.Codecs.Memory
 
         public override SortedSetDocValues GetSortedSet(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 var entry = sortedSets[field.Number];
                 if (!sortedSetInstances.TryGetValue(field.Number, out SortedSetRawValues instance))
@@ -460,6 +477,10 @@ namespace Lucene.Net.Codecs.Memory
                 // Must make a new instance since the iterator has state:
                 return new RandomAccessOrdsAnonymousClass(entry, docToOrdAddress, ords, values);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private class RandomAccessOrdsAnonymousClass : RandomAccessOrds
@@ -536,7 +557,8 @@ namespace Lucene.Net.Codecs.Memory
             else
             {
                 IBits instance;
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (!docsWithFieldInstances.TryGetValue(fieldNumber, out instance))
                     {
@@ -552,6 +574,10 @@ namespace Lucene.Net.Codecs.Memory
                         docsWithFieldInstances[fieldNumber] = instance;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
                 return instance;
             }
         }
diff --git a/src/Lucene.Net.Codecs/Memory/MemoryDocValuesProducer.cs b/src/Lucene.Net.Codecs/Memory/MemoryDocValuesProducer.cs
index 87f0c0c..afff0f1 100644
--- a/src/Lucene.Net.Codecs/Memory/MemoryDocValuesProducer.cs
+++ b/src/Lucene.Net.Codecs/Memory/MemoryDocValuesProducer.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using Lucene.Net.Util.Fst;
 using Lucene.Net.Util.Packed;
@@ -207,7 +208,8 @@ namespace Lucene.Net.Codecs.Memory
 
         public override NumericDocValues GetNumeric(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!numericInstances.TryGetValue(field.Number, out NumericDocValues instance))
                 {
@@ -216,6 +218,10 @@ namespace Lucene.Net.Codecs.Memory
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override long RamBytesUsed() => ramBytesUsed;
@@ -331,7 +337,8 @@ namespace Lucene.Net.Codecs.Memory
 
         public override BinaryDocValues GetBinary(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!binaryInstances.TryGetValue(field.Number, out BinaryDocValues instance))
                 {
@@ -340,6 +347,10 @@ namespace Lucene.Net.Codecs.Memory
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private BinaryDocValues LoadBinary(FieldInfo field)
@@ -409,7 +420,8 @@ namespace Lucene.Net.Codecs.Memory
                 return DocValues.EMPTY_SORTED;
             }
             FST<long?> instance;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!fstInstances.TryGetValue(field.Number, out instance))
                 {
@@ -419,6 +431,10 @@ namespace Lucene.Net.Codecs.Memory
                     fstInstances[field.Number] = instance;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             var docToOrd = GetNumeric(field);
             var fst = instance;
 
@@ -521,7 +537,8 @@ namespace Lucene.Net.Codecs.Memory
                 return DocValues.EMPTY_SORTED_SET; // empty FST!
             }
             FST<long?> instance;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!fstInstances.TryGetValue(field.Number, out instance))
                 {
@@ -531,6 +548,10 @@ namespace Lucene.Net.Codecs.Memory
                     fstInstances[field.Number] = instance;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             var docToOrds = GetBinary(field);
             var fst = instance;
 
@@ -656,7 +677,8 @@ namespace Lucene.Net.Codecs.Memory
             else
             {
                 IBits instance;
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (!docsWithFieldInstances.TryGetValue(fieldNumber, out instance))
                     {
@@ -672,6 +694,10 @@ namespace Lucene.Net.Codecs.Memory
                         docsWithFieldInstances[fieldNumber] = instance;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
                 return instance;
             }
         }
diff --git a/src/Lucene.Net.Codecs/SimpleText/SimpleTextFieldsReader.cs b/src/Lucene.Net.Codecs/SimpleText/SimpleTextFieldsReader.cs
index bf5bf86..01e9897 100644
--- a/src/Lucene.Net.Codecs/SimpleText/SimpleTextFieldsReader.cs
+++ b/src/Lucene.Net.Codecs/SimpleText/SimpleTextFieldsReader.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using Lucene.Net.Util.Fst;
 using System;
@@ -677,7 +678,8 @@ namespace Lucene.Net.Codecs.SimpleText
 
         public override Terms GetTerms(string field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!_termsCache.TryGetValue(field, out SimpleTextTerms terms) || terms == null)
                 {
@@ -694,6 +696,10 @@ namespace Lucene.Net.Codecs.SimpleText
 
                 return terms;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override int Count => -1;
diff --git a/src/Lucene.Net.Facet/FacetsConfig.cs b/src/Lucene.Net.Facet/FacetsConfig.cs
index 735157e..83f60c1 100644
--- a/src/Lucene.Net.Facet/FacetsConfig.cs
+++ b/src/Lucene.Net.Facet/FacetsConfig.cs
@@ -1,6 +1,7 @@
 // Lucene version compatibility level 4.8.1
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -141,7 +142,8 @@ namespace Lucene.Net.Facet
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public virtual DimConfig GetDimConfig(string dimName)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (!fieldTypes.TryGetValue(dimName, out DimConfig ft))
                 {
@@ -149,6 +151,10 @@ namespace Lucene.Net.Facet
                 }
                 return ft;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -158,7 +164,8 @@ namespace Lucene.Net.Facet
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public virtual void SetHierarchical(string dimName, bool v)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // LUCENENET: Eliminated extra lookup by using TryGetValue instead of ContainsKey
                 if (!fieldTypes.TryGetValue(dimName, out DimConfig fieldType))
@@ -170,6 +177,10 @@ namespace Lucene.Net.Facet
                     fieldType.IsHierarchical = v;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -179,7 +190,8 @@ namespace Lucene.Net.Facet
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public virtual void SetMultiValued(string dimName, bool v)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // LUCENENET: Eliminated extra lookup by using TryGetValue instead of ContainsKey
                 if (!fieldTypes.TryGetValue(dimName, out DimConfig fieldType))
@@ -191,6 +203,10 @@ namespace Lucene.Net.Facet
                     fieldType.IsMultiValued = v;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -201,7 +217,8 @@ namespace Lucene.Net.Facet
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public virtual void SetRequireDimCount(string dimName, bool v)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // LUCENENET: Eliminated extra lookup by using TryGetValue instead of ContainsKey
                 if (!fieldTypes.TryGetValue(dimName, out DimConfig fieldType))
@@ -213,6 +230,10 @@ namespace Lucene.Net.Facet
                     fieldType.RequireDimCount = v;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -222,7 +243,8 @@ namespace Lucene.Net.Facet
         /// </summary>
         public virtual void SetIndexFieldName(string dimName, string indexFieldName)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // LUCENENET: Eliminated extra lookup by using TryGetValue instead of ContainsKey
                 if (!fieldTypes.TryGetValue(dimName, out DimConfig fieldType))
@@ -234,6 +256,10 @@ namespace Lucene.Net.Facet
                     fieldType.IndexFieldName = indexFieldName;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs b/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs
index e7a2dd5..c9a9748 100644
--- a/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs
@@ -1,5 +1,6 @@
 // Lucene version compatibility level 4.8.1
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;
@@ -82,7 +83,8 @@ namespace Lucene.Net.Facet.Taxonomy
         {
             // LUCENENET NOTE: Since ConditionalWeakTable doesn't synchronize on enumeration in the RamBytesUsed() method,
             // the lock is still required here despite it being a threadsafe collection.
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 object cacheKey = context.Reader.CoreCacheKey;
                 if (!ordsCache.TryGetValue(cacheKey, out CachedOrds ords))
@@ -97,6 +99,10 @@ namespace Lucene.Net.Facet.Taxonomy
                 }
                 return ords;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public override string IndexFieldName => source.IndexFieldName;
@@ -198,7 +204,8 @@ namespace Lucene.Net.Facet.Taxonomy
 
         public virtual long RamBytesUsed()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 long bytes = 0;
                 foreach (var pair in ordsCache)
@@ -208,6 +215,10 @@ namespace Lucene.Net.Facet.Taxonomy
 
                 return bytes;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyWriter.cs b/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyWriter.cs
index e15c06a..7a478e7 100644
--- a/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyWriter.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyWriter.cs
@@ -6,6 +6,7 @@ using Lucene.Net.Index;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -306,7 +307,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         {
             if (!initializedReaderManager)
             {
-                lock (syncLock)
+                UninterruptableMonitor.Enter(syncLock);
+                try
                 {
                     // verify that the taxo-writer hasn't been closed on us.
                     EnsureOpen();
@@ -317,6 +319,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                         initializedReaderManager = true;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncLock);
+                }
             }
         }
 
@@ -370,7 +376,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         /// </summary>
         protected virtual void Dispose(bool disposing)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (disposing && !isClosed)
                 {
@@ -378,6 +385,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                     DoClose();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private void DoClose()
@@ -393,7 +404,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         /// </summary>
         private void CloseResources() // LUCENENET: Made private, since this has the same purpose as Dispose(bool).
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (initializedReaderManager)
                 {
@@ -404,6 +416,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 cache?.Dispose();
                 parentStream.Dispose(); // LUCENENET specific
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -413,7 +429,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         /// </summary>
         protected virtual int FindCategory(FacetLabel categoryPath)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // If we can find the category in the cache, or we know the cache is
                 // complete, we can return the response directly from it
@@ -480,6 +497,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 }
                 return doc;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public virtual int AddCategory(FacetLabel categoryPath)
@@ -491,7 +512,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
             if (res < 0)
             {
                 // the category is not in the cache - following code cannot be executed in parallel.
-                lock (syncLock)
+                UninterruptableMonitor.Enter(syncLock);
+                try
                 {
                     res = FindCategory(categoryPath);
                     if (res < 0)
@@ -505,6 +527,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                         res = InternalAddCategory(categoryPath);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncLock);
+                }
             }
             return res;
         }
@@ -671,7 +697,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
 
         private void RefreshReaderManager()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // this method is synchronized since it cannot happen concurrently with
                 // addCategoryDocument -- when this method returns, we must know that the
@@ -686,11 +713,16 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                     shouldRefreshReaderManager = false;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public virtual void Commit()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 EnsureOpen();
                 // LUCENE-4972: if we always call setCommitData, we create empty commits
@@ -702,6 +734,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 }
                 indexWriter.Commit();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -730,7 +766,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         /// </summary>
         public virtual void PrepareCommit()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 EnsureOpen();
                 // LUCENE-4972: if we always call setCommitData, we create empty commits
@@ -742,6 +779,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 }
                 indexWriter.PrepareCommit();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public virtual int Count
@@ -784,7 +825,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         // complete or not.
         private void PerhapsFillCache()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (cacheMisses < cacheMissesUntilFill)
                 {
@@ -849,7 +891,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 cacheIsComplete = !aborted;
                 if (cacheIsComplete)
                 {
-                    lock (syncLock)
+                    UninterruptableMonitor.Enter(syncLock); // LUCENENET TODO: Do we need to synchroize again since the whole method is synchronized?
+                    try
                     {
                         // everything is in the cache, so no need to keep readerManager open.
                         // this block is executed in a sync block so that it works well with
@@ -858,15 +901,24 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                         readerManager = null;
                         initializedReaderManager = false;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(syncLock);
+                    }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private TaxonomyIndexArrays GetTaxoArrays()
         {
             if (taxoArrays is null)
             {
-                lock (syncLock)
+                UninterruptableMonitor.Enter(syncLock);
+                try
                 {
                     if (taxoArrays is null)
                     {
@@ -886,6 +938,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncLock);
+                }
             }
             return taxoArrays;
         }
@@ -1118,7 +1174,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         /// </summary>
         public virtual void Rollback()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 EnsureOpen();
                 indexWriter.Rollback();
@@ -1130,6 +1187,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 // subclasses to provide their own dipsosable implementation.
                 Dispose();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
@@ -1140,7 +1201,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
         /// </summary>
         public virtual void ReplaceTaxonomy(Directory taxoDir)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // replace the taxonomy by doing IW optimized operations
                 indexWriter.DeleteAll();
@@ -1161,6 +1223,10 @@ namespace Lucene.Net.Facet.Taxonomy.Directory
                 // update indexEpoch as a taxonomy replace is just like it has be recreated
                 ++indexEpoch;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Facet/Taxonomy/TaxonomyReader.cs b/src/Lucene.Net.Facet/Taxonomy/TaxonomyReader.cs
index 556faaf..761edd2 100644
--- a/src/Lucene.Net.Facet/Taxonomy/TaxonomyReader.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/TaxonomyReader.cs
@@ -1,6 +1,7 @@
 // Lucene version compatibility level 4.8.1
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -181,12 +182,17 @@ namespace Lucene.Net.Facet.Taxonomy
 #pragma warning restore CA1063 // Implement IDisposable Correctly
         {
             if (closed) return;
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (closed) return;
                 DecRef();
                 closed = true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
             Dispose(true);
             GC.SuppressFinalize(this);
         }
diff --git a/src/Lucene.Net.Facet/Taxonomy/WriterCache/Cl2oTaxonomyWriterCache.cs b/src/Lucene.Net.Facet/Taxonomy/WriterCache/Cl2oTaxonomyWriterCache.cs
index 0239cbf..4f9f8b0 100644
--- a/src/Lucene.Net.Facet/Taxonomy/WriterCache/Cl2oTaxonomyWriterCache.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/WriterCache/Cl2oTaxonomyWriterCache.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 4.8.1
+using Lucene.Net.Support.Threading;
 using System;
 using System.Threading;
 
@@ -80,7 +81,8 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
 
                 // LUCENENET: Use additional lock to ensure our ReaderWriterLockSlim only gets
                 // disposed by the first caller.
-                lock (disposalLock)
+                UninterruptableMonitor.Enter(disposalLock);
+                try
                 {
                     if (isDisposed) return;
                     syncLock.EnterWriteLock();
@@ -95,6 +97,10 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
                         syncLock.Dispose();
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(disposalLock);
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Facet/Taxonomy/WriterCache/LruTaxonomyWriterCache.cs b/src/Lucene.Net.Facet/Taxonomy/WriterCache/LruTaxonomyWriterCache.cs
index 484fc3a..9dd5d40 100644
--- a/src/Lucene.Net.Facet/Taxonomy/WriterCache/LruTaxonomyWriterCache.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/WriterCache/LruTaxonomyWriterCache.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 4.8.1
+using Lucene.Net.Support.Threading;
 using System;
 
 namespace Lucene.Net.Facet.Taxonomy.WriterCache
@@ -90,19 +91,29 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
         {
             get
             {
-                lock (syncLock)
+                UninterruptableMonitor.Enter(syncLock);
+                try
                 {
                     return cache.Count == cache.Limit;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncLock);
+                }
             }
         }
 
         public virtual void Clear()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 cache.Clear();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public void Dispose()
@@ -116,7 +127,8 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
             if (disposing)
             {
                 if (isDisposed) return;
-                lock (syncLock)
+                UninterruptableMonitor.Enter(syncLock);
+                try
                 {
                     if (isDisposed) return;
                     if (cache != null)
@@ -126,20 +138,30 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
                     }
                     isDisposed = true;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncLock);
+                }
             }
         }
 
         public virtual int Get(FacetLabel categoryPath)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 return cache.TryGetValue(categoryPath, out int result) ? result : -1;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public virtual bool Put(FacetLabel categoryPath, int ordinal)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 bool ret = cache.Put(categoryPath, ordinal);
                 // If the cache is full, we need to clear one or more old entries
@@ -155,6 +177,10 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
                 }
                 return ret;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net.Facet/Taxonomy/WriterCache/NameIntCacheLRU.cs b/src/Lucene.Net.Facet/Taxonomy/WriterCache/NameIntCacheLRU.cs
index b17e5c7..e189275 100644
--- a/src/Lucene.Net.Facet/Taxonomy/WriterCache/NameIntCacheLRU.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/WriterCache/NameIntCacheLRU.cs
@@ -1,5 +1,6 @@
 // Lucene version compatibility level 4.8.1
 using J2N.Collections.Concurrent;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -228,7 +229,8 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
                 return false;
             }
 
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 // Double-check that another thread didn't beat us to the operation
                 n = cache.Count - (2 * maxCacheSize) / 3;
@@ -246,6 +248,10 @@ namespace Lucene.Net.Facet.Taxonomy.WriterCache
                     i++;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
             return true;
         }
     }
diff --git a/src/Lucene.Net.Grouping/AbstractFirstPassGroupingCollector.cs b/src/Lucene.Net.Grouping/AbstractFirstPassGroupingCollector.cs
index f9fca90..bd8e559 100644
--- a/src/Lucene.Net.Grouping/AbstractFirstPassGroupingCollector.cs
+++ b/src/Lucene.Net.Grouping/AbstractFirstPassGroupingCollector.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -242,11 +243,16 @@ namespace Lucene.Net.Search.Grouping
                 // the bottom group with this new group.
                 //CollectedSearchGroup<TGroupValue> bottomGroup = orderedGroups.PollLast();
                 CollectedSearchGroup<TGroupValue> bottomGroup;
-                lock (m_orderedGroups)
+                UninterruptableMonitor.Enter(m_orderedGroups);
+                try
                 {
                     bottomGroup = m_orderedGroups.Last();
                     m_orderedGroups.Remove(bottomGroup);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_orderedGroups);
+                }
                 if (Debugging.AssertsEnabled) Debugging.Assert(m_orderedGroups.Count == topNGroups - 1);
 
                 groupMap.Remove(bottomGroup.GroupValue);
@@ -309,11 +315,16 @@ namespace Lucene.Net.Search.Grouping
             CollectedSearchGroup<TGroupValue> prevLast;
             if (m_orderedGroups != null)
             {
-                lock (m_orderedGroups)
+                UninterruptableMonitor.Enter(m_orderedGroups);
+                try
                 {
                     prevLast = m_orderedGroups.Last();
                     m_orderedGroups.Remove(group);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_orderedGroups);
+                }
                 if (Debugging.AssertsEnabled) Debugging.Assert(m_orderedGroups.Count == topNGroups - 1);
             }
             else
diff --git a/src/Lucene.Net.Misc/Document/LazyDocument.cs b/src/Lucene.Net.Misc/Document/LazyDocument.cs
index f64d0fd..82d2db9 100644
--- a/src/Lucene.Net.Misc/Document/LazyDocument.cs
+++ b/src/Lucene.Net.Misc/Document/LazyDocument.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Analysis;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -76,7 +77,8 @@ namespace Lucene.Net.Documents
             LazyField value = new LazyField(this, fieldInfo.Name, fieldInfo.Number);
             values.Add(value);
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // edge case: if someone asks this LazyDoc for more LazyFields
                 // after other LazyFields from the same LazyDoc have been
@@ -84,6 +86,10 @@ namespace Lucene.Net.Documents
                 // so the new LazyFields are also populated.
                 doc = null;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             return value;
         }
 
@@ -93,7 +99,8 @@ namespace Lucene.Net.Documents
         /// </summary>
         internal virtual Document GetDocument()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (doc == null)
                 {
@@ -108,6 +115,10 @@ namespace Lucene.Net.Documents
                 }
                 return doc;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // :TODO: synchronize to prevent redundent copying? (sync per field name?)
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/BasicQueryFactory.cs b/src/Lucene.Net.QueryParser/Surround/Query/BasicQueryFactory.cs
index 0858294..e7c6fb6 100644
--- a/src/Lucene.Net.QueryParser/Surround/Query/BasicQueryFactory.cs
+++ b/src/Lucene.Net.QueryParser/Surround/Query/BasicQueryFactory.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Index;
 using Lucene.Net.Search;
 using Lucene.Net.Search.Spans;
+using Lucene.Net.Support.Threading;
 using System.Runtime.CompilerServices;
 
 namespace Lucene.Net.QueryParsers.Surround.Query
@@ -69,13 +70,18 @@ namespace Lucene.Net.QueryParsers.Surround.Query
 
         protected virtual void CheckMax()
         {
-            lock (_lock) 
+            UninterruptableMonitor.Enter(_lock);
+            try
             {
                 if (AtMax)
                     throw new TooManyBasicQueries(MaxBasicQueries);
 
                 queriesMade++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(_lock);
+            }
         }
 
         public virtual TermQuery NewTermQuery(Term term)
diff --git a/src/Lucene.Net.QueryParser/Xml/Builders/CachedFilterBuilder.cs b/src/Lucene.Net.QueryParser/Xml/Builders/CachedFilterBuilder.cs
index 825161c..27e1313 100644
--- a/src/Lucene.Net.QueryParser/Xml/Builders/CachedFilterBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Xml/Builders/CachedFilterBuilder.cs
@@ -1,5 +1,6 @@
 using J2N.Collections.Concurrent;
 using Lucene.Net.Search;
+using Lucene.Net.Support.Threading;
 using System.Xml;
 
 namespace Lucene.Net.QueryParsers.Xml.Builders
@@ -56,7 +57,8 @@ namespace Lucene.Net.QueryParsers.Xml.Builders
 
         public virtual Filter GetFilter(XmlElement e)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 XmlElement childElement = DOMUtils.GetFirstChildOrFail(e);
 
@@ -99,6 +101,10 @@ namespace Lucene.Net.QueryParsers.Xml.Builders
                 filterCache[cacheKey] = cachedFilter;
                 return cachedFilter;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // LUCENENET NOTE: LRUCache replaced with LurchTable
diff --git a/src/Lucene.Net.QueryParser/Xml/Builders/UserInputQueryBuilder.cs b/src/Lucene.Net.QueryParser/Xml/Builders/UserInputQueryBuilder.cs
index 992e361..9c5b8bf 100644
--- a/src/Lucene.Net.QueryParser/Xml/Builders/UserInputQueryBuilder.cs
+++ b/src/Lucene.Net.QueryParser/Xml/Builders/UserInputQueryBuilder.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Analysis;
 using Lucene.Net.QueryParsers.Classic;
 using Lucene.Net.Search;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System.Xml;
 
@@ -65,10 +66,15 @@ namespace Lucene.Net.QueryParsers.Xml.Builders
                 if (unSafeParser != null)
                 {
                     //synchronize on unsafe parser
-                    lock (unSafeParser)
+                    UninterruptableMonitor.Enter(unSafeParser);
+                    try
                     {
                         q = unSafeParser.Parse(text);
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(unSafeParser);
+                    }
                 }
                 else
                 {
diff --git a/src/Lucene.Net.Replicator/LocalReplicator.cs b/src/Lucene.Net.Replicator/LocalReplicator.cs
index 1129421..aee5c18 100644
--- a/src/Lucene.Net.Replicator/LocalReplicator.cs
+++ b/src/Lucene.Net.Replicator/LocalReplicator.cs
@@ -1,4 +1,5 @@
 using J2N.Threading.Atomic;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -159,18 +160,24 @@ namespace Lucene.Net.Replicator
         /// <exception cref="ObjectDisposedException">This replicator has already been disposed.</exception>
         protected void EnsureOpen()
         {
-            lock (padlock)
+            UninterruptableMonitor.Enter(padlock);
+            try
             {
                 if (!disposed)
                     return;
 
                 throw AlreadyClosedException.Create(this.GetType().FullName, "This replicator has already been disposed.");
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(padlock);
+            }
         }
 
         public virtual SessionToken CheckForUpdate(string currentVersion)
         {
-            lock (padlock)
+            UninterruptableMonitor.Enter(padlock);
+            try
             {
                 EnsureOpen();
                 if (currentRevision == null)
@@ -187,6 +194,10 @@ namespace Lucene.Net.Replicator
                 sessions[sessionID] = new ReplicationSession(token, currentRevision);
                 return token;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(padlock);
+            }
         }
 
         protected virtual void Dispose(bool disposing)
@@ -194,12 +205,17 @@ namespace Lucene.Net.Replicator
             if (disposed || !disposing)
                 return;
 
-            lock (padlock)
+            UninterruptableMonitor.Enter(padlock);
+            try
             {
                 foreach (ReplicationSession session in sessions.Values)
                     session.Revision.DecRef();
                 sessions.Clear();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(padlock);
+            }
             disposed = true;
         }
 
@@ -221,18 +237,24 @@ namespace Lucene.Net.Replicator
             get => expirationThreshold;
             set
             {
-                lock (padlock)
+                UninterruptableMonitor.Enter(padlock);
+                try
                 {
                     EnsureOpen();
                     expirationThreshold = value;
                     CheckExpiredSessions();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(padlock);
+                }
             }
         }
 
         public virtual Stream ObtainFile(string sessionId, string source, string fileName)
         {
-            lock (padlock)
+            UninterruptableMonitor.Enter(padlock);
+            try
             {
                 EnsureOpen();
 
@@ -249,11 +271,16 @@ namespace Lucene.Net.Replicator
                 sessions[sessionId].MarkAccessed();
                 return session.Revision.Revision.Open(source, fileName);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(padlock);
+            }
         }
 
         public virtual void Publish(IRevision revision)
         {
-            lock (padlock)
+            UninterruptableMonitor.Enter(padlock);
+            try
             {
                 EnsureOpen();
 
@@ -281,16 +308,25 @@ namespace Lucene.Net.Replicator
 
                 CheckExpiredSessions();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(padlock);
+            }
         }
 
         /// <exception cref="InvalidOperationException"></exception>
         public virtual void Release(string sessionId)
         {
-            lock (padlock)
+            UninterruptableMonitor.Enter(padlock);
+            try
             {
                 EnsureOpen();
                 ReleaseSession(sessionId);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(padlock);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs b/src/Lucene.Net.Replicator/ReplicationClient.cs
index e0c0164..9d05757 100644
--- a/src/Lucene.Net.Replicator/ReplicationClient.cs
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -91,12 +91,17 @@ namespace Lucene.Net.Replicator
             /// </summary>
             public void Start()
             {
-                lock (controlLock)
+                UninterruptableMonitor.Enter(controlLock);
+                try
                 {
                     if (IsAlive)
                         return;
                     IsAlive = true;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(controlLock);
+                }
                 RegisterWait(interval);
             }
 
@@ -105,12 +110,17 @@ namespace Lucene.Net.Replicator
             /// </summary>
             public void Stop()
             {
-                lock (controlLock)
+                UninterruptableMonitor.Enter(controlLock);
+                try
                 {
                     if (!IsAlive)
                         return;
                     IsAlive = false;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(controlLock);
+                }
                 stopHandle = new AutoResetEvent(false);
 
                 //NOTE: Execute any outstanding, this execution will terminate almost instantaniously if it's not already running.
diff --git a/src/Lucene.Net.Suggest/Spell/SpellChecker.cs b/src/Lucene.Net.Suggest/Spell/SpellChecker.cs
index bbfc0ba..23c4e39 100644
--- a/src/Lucene.Net.Suggest/Spell/SpellChecker.cs
+++ b/src/Lucene.Net.Suggest/Spell/SpellChecker.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -144,8 +145,9 @@ namespace Lucene.Net.Search.Spell
         public virtual void SetSpellIndex(Directory spellIndexDir)
         {
             // this could be the same directory as the current spellIndex
-            // modifications to the directory should be synchronized 
-            lock (modifyCurrentIndexLock)
+            // modifications to the directory should be synchronized
+            UninterruptableMonitor.Enter(modifyCurrentIndexLock);
+            try
             {
                 EnsureOpen();
                 if (!DirectoryReader.IndexExists(spellIndexDir))
@@ -156,6 +158,10 @@ namespace Lucene.Net.Search.Spell
                 }
                 SwapSearcher(spellIndexDir);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(modifyCurrentIndexLock);
+            }
         }
 
         /// <summary>
@@ -442,7 +448,8 @@ namespace Lucene.Net.Search.Spell
         /// <exception cref="ObjectDisposedException"> if the Spellchecker is already closed </exception>
         public virtual void ClearIndex()
         {
-            lock (modifyCurrentIndexLock)
+            UninterruptableMonitor.Enter(modifyCurrentIndexLock);
+            try
             {
                 EnsureOpen();
                 var dir = this.spellIndex;
@@ -452,6 +459,10 @@ namespace Lucene.Net.Search.Spell
 #pragma warning restore 612, 618
                 SwapSearcher(dir);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(modifyCurrentIndexLock);
+            }
         }
 
         /// <summary>
@@ -485,7 +496,8 @@ namespace Lucene.Net.Search.Spell
         /// <exception cref="IOException"> If there is a low-level I/O error. </exception>
         public void IndexDictionary(IDictionary dict, IndexWriterConfig config, bool fullMerge)
         {
-            lock (modifyCurrentIndexLock)
+            UninterruptableMonitor.Enter(modifyCurrentIndexLock);
+            try
             {
                 EnsureOpen();
                 Directory dir = this.spellIndex;
@@ -558,6 +570,10 @@ namespace Lucene.Net.Search.Spell
                 // is fetched:
                 SwapSearcher(dir);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(modifyCurrentIndexLock);
+            }
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -634,12 +650,17 @@ namespace Lucene.Net.Search.Spell
 
         private IndexSearcher ObtainSearcher()
         {
-            lock (searcherLock)
+            UninterruptableMonitor.Enter(searcherLock);
+            try
             {
                 EnsureOpen();
                 searcher.IndexReader.IncRef();
                 return searcher;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(searcherLock);
+            }
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -681,12 +702,17 @@ namespace Lucene.Net.Search.Spell
         {
             if (disposing && !disposed)
             {
-                lock (searcherLock)
+                UninterruptableMonitor.Enter(searcherLock);
+                try
                 {
                     disposed = true;
                     searcher?.IndexReader?.Dispose();
                     searcher = null;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(searcherLock);
+                }
             }
         }
 
@@ -698,7 +724,8 @@ namespace Lucene.Net.Search.Spell
              * this operation than block access to the current searcher while opening.
              */
             IndexSearcher indexSearcher = CreateSearcher(dir);
-            lock (searcherLock)
+            UninterruptableMonitor.Enter(searcherLock);
+            try
             {
                 if (disposed)
                 {
@@ -710,6 +737,10 @@ namespace Lucene.Net.Search.Spell
                 searcher = indexSearcher;
                 this.spellIndex = dir;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(searcherLock);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Suggest/Suggest/Analyzing/AnalyzingInfixSuggester.cs b/src/Lucene.Net.Suggest/Suggest/Analyzing/AnalyzingInfixSuggester.cs
index a3e5f77..3a084a3 100644
--- a/src/Lucene.Net.Suggest/Suggest/Analyzing/AnalyzingInfixSuggester.cs
+++ b/src/Lucene.Net.Suggest/Suggest/Analyzing/AnalyzingInfixSuggester.cs
@@ -13,6 +13,7 @@ using System.IO;
 using System.Text;
 using JCG = J2N.Collections.Generic;
 using Directory = Lucene.Net.Store.Directory;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Search.Suggest.Analyzing
 {
@@ -328,7 +329,8 @@ namespace Lucene.Net.Search.Suggest.Analyzing
             if (writer != null)
                 return;
 
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (writer == null)
                 {
@@ -341,6 +343,10 @@ namespace Lucene.Net.Search.Suggest.Analyzing
                     m_searcherMgr = new SearcherManager(writer, true, null);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletionLookup.cs b/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletionLookup.cs
index 76c6727..afacc7d 100644
--- a/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletionLookup.cs
+++ b/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletionLookup.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Store;
 using Lucene.Net.Support;
 using Lucene.Net.Support.IO;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using Lucene.Net.Util.Fst;
 using System;
@@ -299,7 +300,8 @@ namespace Lucene.Net.Search.Suggest.Fst
 
         public override bool Store(DataOutput output)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 output.WriteVInt64(count);
                 if (this.normalCompletion == null || normalCompletion.FST == null)
@@ -309,17 +311,26 @@ namespace Lucene.Net.Search.Suggest.Fst
                 normalCompletion.FST.Save(output);
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override bool Load(DataInput input)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 count = input.ReadVInt64();
                 this.higherWeightsCompletion = new FSTCompletion(new FST<object>(input, NoOutputs.Singleton));
                 this.normalCompletion = new FSTCompletion(higherWeightsCompletion.FST, false, exactMatchFirst);
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override long GetSizeInBytes()
diff --git a/src/Lucene.Net.Suggest/Suggest/Tst/TSTLookup.cs b/src/Lucene.Net.Suggest/Suggest/Tst/TSTLookup.cs
index 887f627..a46c9f1 100644
--- a/src/Lucene.Net.Suggest/Suggest/Tst/TSTLookup.cs
+++ b/src/Lucene.Net.Suggest/Suggest/Tst/TSTLookup.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -261,23 +262,33 @@ namespace Lucene.Net.Search.Suggest.Tst
 
         public override bool Store(DataOutput output)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 output.WriteVInt64(count);
                 WriteRecursively(output, root);
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override bool Load(DataInput input)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 count = input.ReadVInt64();
                 root = new TernaryTreeNode();
                 ReadRecursively(input, root);
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.TestFramework/Index/BaseDocValuesFormatTestCase.cs b/src/Lucene.Net.TestFramework/Index/BaseDocValuesFormatTestCase.cs
index a270fe8..e04602f 100644
--- a/src/Lucene.Net.TestFramework/Index/BaseDocValuesFormatTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Index/BaseDocValuesFormatTestCase.cs
@@ -17,6 +17,7 @@ using Assert = Lucene.Net.TestFramework.Assert;
 using static Lucene.Net.Index.TermsEnum;
 using J2N.Collections.Generic.Extensions;
 using RandomizedTesting.Generators;
+using Lucene.Net.Support.Threading;
 
 #if TESTFRAMEWORK_MSTEST
 using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute;
diff --git a/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs b/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs
index a3e2aa0..2f92e96 100644
--- a/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs
@@ -7,6 +7,7 @@ using Lucene.Net.Index.Extensions;
 using Lucene.Net.Search;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using RandomizedTesting.Generators;
 using System;
diff --git a/src/Lucene.Net.Tests.Analysis.Common/Analysis/Th/TestThaiAnalyzer.cs b/src/Lucene.Net.Tests.Analysis.Common/Analysis/Th/TestThaiAnalyzer.cs
index 218abd1..3ec5ce9 100644
--- a/src/Lucene.Net.Tests.Analysis.Common/Analysis/Th/TestThaiAnalyzer.cs
+++ b/src/Lucene.Net.Tests.Analysis.Common/Analysis/Th/TestThaiAnalyzer.cs
@@ -5,6 +5,7 @@ using Lucene.Net.Analysis.Core;
 using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Analysis.Util;
 using Lucene.Net.Attributes;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests.Analysis.ICU/Analysis/Icu/Segmentation/TestICUTokenizer.cs b/src/Lucene.Net.Tests.Analysis.ICU/Analysis/Icu/Segmentation/TestICUTokenizer.cs
index 2a40b41..892ffce 100644
--- a/src/Lucene.Net.Tests.Analysis.ICU/Analysis/Icu/Segmentation/TestICUTokenizer.cs
+++ b/src/Lucene.Net.Tests.Analysis.ICU/Analysis/Icu/Segmentation/TestICUTokenizer.cs
@@ -3,6 +3,7 @@ using ICU4N.Globalization;
 using J2N.Threading;
 using Lucene.Net.Analysis.Icu.TokenAttributes;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests.Benchmark/ByTask/Tasks/CountingSearchTestTask.cs b/src/Lucene.Net.Tests.Benchmark/ByTask/Tasks/CountingSearchTestTask.cs
index 8322fdf..13336eb 100644
--- a/src/Lucene.Net.Tests.Benchmark/ByTask/Tasks/CountingSearchTestTask.cs
+++ b/src/Lucene.Net.Tests.Benchmark/ByTask/Tasks/CountingSearchTestTask.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Benchmarks.ByTask.Tasks
 {
@@ -45,7 +46,8 @@ namespace Lucene.Net.Benchmarks.ByTask.Tasks
 
         private static void IncrNumSearches()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 prevLastMillis = lastMillis;
                 lastMillis = J2N.Time.NanoTime() / J2N.Time.MillisecondsPerNanosecond; // LUCENENET: Use NanoTime() rather than CurrentTimeMilliseconds() for more accurate/reliable results
@@ -55,6 +57,10 @@ namespace Lucene.Net.Benchmarks.ByTask.Tasks
                 }
                 numSearches++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public long GetElapsedMillis()
diff --git a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
index 40e98a6..0600431 100644
--- a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
+++ b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
@@ -1,4 +1,5 @@
 // Lucene version compatibility level 4.8.1
+using Lucene.Net.Support.Threading;
 using RandomizedTesting.Generators;
 using System;
 using System.Threading;
@@ -69,7 +70,7 @@ namespace Lucene.Net.Facet
             return base.OpenInput(name, context);
         }
 
-        internal virtual void doSleep(Random random, int length)
+        internal virtual void DoSleep(Random random, int length)
         {
             int sTime = length < 10 ? sleepMillis : (int)(sleepMillis * Math.Log(length));
             if (random != null)
@@ -89,7 +90,7 @@ namespace Lucene.Net.Facet
 
         /// <summary>
         /// Make a private random. </summary>
-        internal virtual Random forkRandom()
+        internal virtual Random ForkRandom()
         {
             if (random == null)
             {
@@ -114,7 +115,7 @@ namespace Lucene.Net.Facet
                 : base("SlowIndexInput(" + ii + ")")
             {
                 this.outerInstance = outerInstance;
-                this.rand = outerInstance.forkRandom();
+                this.rand = outerInstance.ForkRandom();
                 this.ii = ii;
             }
 
@@ -122,7 +123,7 @@ namespace Lucene.Net.Facet
             {
                 if (numRead >= IO_SLEEP_THRESHOLD)
                 {
-                    outerInstance.doSleep(rand, 0);
+                    outerInstance.DoSleep(rand, 0);
                     numRead = 0;
                 }
                 ++numRead;
@@ -133,7 +134,7 @@ namespace Lucene.Net.Facet
             {
                 if (numRead >= IO_SLEEP_THRESHOLD)
                 {
-                    outerInstance.doSleep(rand, len);
+                    outerInstance.DoSleep(rand, len);
                     numRead = 0;
                 }
                 numRead += len;
@@ -192,14 +193,14 @@ namespace Lucene.Net.Facet
             {
                 this.outerInstance = outerInstance;
                 this.io = io;
-                this.rand = outerInstance.forkRandom();
+                this.rand = outerInstance.ForkRandom();
             }
 
             public override void WriteByte(byte b)
             {
                 if (numWrote >= IO_SLEEP_THRESHOLD)
                 {
-                    outerInstance.doSleep(rand, 0);
+                    outerInstance.DoSleep(rand, 0);
                     numWrote = 0;
                 }
                 ++numWrote;
@@ -210,7 +211,7 @@ namespace Lucene.Net.Facet
             {
                 if (numWrote >= IO_SLEEP_THRESHOLD)
                 {
-                    outerInstance.doSleep(rand, length);
+                    outerInstance.DoSleep(rand, length);
                     numWrote = 0;
                 }
                 numWrote += length;
diff --git a/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs b/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs
index 43fa461..f608ee9 100644
--- a/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs
+++ b/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs
@@ -4,6 +4,7 @@ using J2N.Threading.Atomic;
 using Lucene.Net.Attributes;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Search;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
diff --git a/src/Lucene.Net.Tests.Facet/Taxonomy/TestTaxonomyCombined.cs b/src/Lucene.Net.Tests.Facet/Taxonomy/TestTaxonomyCombined.cs
index 9efbb73..8504348 100644
--- a/src/Lucene.Net.Tests.Facet/Taxonomy/TestTaxonomyCombined.cs
+++ b/src/Lucene.Net.Tests.Facet/Taxonomy/TestTaxonomyCombined.cs
@@ -2,6 +2,7 @@
 using J2N.Threading;
 using J2N.Threading.Atomic;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
@@ -904,6 +905,7 @@ namespace Lucene.Net.Facet.Taxonomy
                         int lastOrd = tr.ParallelTaxonomyArrays.Parents.Length - 1;
                         Assert.IsNotNull(tr.GetPath(lastOrd), "path of last-ord " + lastOrd + " is not found!");
                         AssertChildrenArrays(tr.ParallelTaxonomyArrays, retry, retrieval[0]++);
+
                         Thread.Sleep(10);// don't starve refresh()'s CPU, which sleeps every 50 bytes for 1 ms
                     }
                 }
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
index d19a252..7e5569e 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -8,6 +8,7 @@ using Lucene.Net.Facet.Taxonomy.Directory;
 using Lucene.Net.Index;
 using Lucene.Net.Search;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
index de3040f..89e0412 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -4,6 +4,7 @@ using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
index 4ec7450..f11a460 100644
--- a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests.Suggest/Spell/TestSpellChecker.cs b/src/Lucene.Net.Tests.Suggest/Spell/TestSpellChecker.cs
index 3b1db40..db6906d 100644
--- a/src/Lucene.Net.Tests.Suggest/Spell/TestSpellChecker.cs
+++ b/src/Lucene.Net.Tests.Suggest/Spell/TestSpellChecker.cs
@@ -5,6 +5,7 @@ using Lucene.Net.Documents;
 using Lucene.Net.Index;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests.Suggest/Suggest/Analyzing/AnalyzingInfixSuggesterTest.cs b/src/Lucene.Net.Tests.Suggest/Suggest/Analyzing/AnalyzingInfixSuggesterTest.cs
index b66fc36..b65f88e 100644
--- a/src/Lucene.Net.Tests.Suggest/Suggest/Analyzing/AnalyzingInfixSuggesterTest.cs
+++ b/src/Lucene.Net.Tests.Suggest/Suggest/Analyzing/AnalyzingInfixSuggesterTest.cs
@@ -5,6 +5,7 @@ using Lucene.Net.Analysis;
 using Lucene.Net.Analysis.Core;
 using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Analysis.Util;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests/Index/TestAddIndexes.cs b/src/Lucene.Net.Tests/Index/TestAddIndexes.cs
index a44c384..77a53a0 100644
--- a/src/Lucene.Net.Tests/Index/TestAddIndexes.cs
+++ b/src/Lucene.Net.Tests/Index/TestAddIndexes.cs
@@ -4,6 +4,7 @@ using Lucene.Net.Codecs;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
@@ -756,10 +757,15 @@ namespace Lucene.Net.Index
             internal override void Handle(Exception t)
             {
                 t.printStackTrace(Console.Out);
-                lock (failures)
+                UninterruptableMonitor.Enter(failures);
+                try
                 {
                     failures.Add(t);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(failures);
+                }
             }
 
             internal override void DoBody(int j, Directory[] dirs)
@@ -856,10 +862,15 @@ namespace Lucene.Net.Index
                 if (!t.IsAlreadyClosedException() && !t.IsNullPointerException())
                 {
                     t.printStackTrace(Console.Out);
-                    lock (failures)
+                    UninterruptableMonitor.Enter(failures);
+                    try
                     {
                         failures.Add(t);
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(failures);
+                    }
                 }
             }
         }
@@ -961,10 +972,15 @@ namespace Lucene.Net.Index
                 if (report)
                 {
                     t.printStackTrace(Console.Out);
-                    lock (failures)
+                    UninterruptableMonitor.Enter(failures);
+                    try
                     {
                         failures.Add(t);
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(failures);
+                    }
                 }
             }
         }
diff --git a/src/Lucene.Net.Tests/Index/TestBagOfPositions.cs b/src/Lucene.Net.Tests/Index/TestBagOfPositions.cs
index e4005d9..ec324b7 100644
--- a/src/Lucene.Net.Tests/Index/TestBagOfPositions.cs
+++ b/src/Lucene.Net.Tests/Index/TestBagOfPositions.cs
@@ -1,6 +1,7 @@
 using J2N.Collections.Generic.Extensions;
 using J2N.Threading;
 using Lucene.Net.Documents;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
 using System;
diff --git a/src/Lucene.Net.Tests/Index/TestBagOfPostings.cs b/src/Lucene.Net.Tests/Index/TestBagOfPostings.cs
index fcdd33e..0965fb3 100644
--- a/src/Lucene.Net.Tests/Index/TestBagOfPostings.cs
+++ b/src/Lucene.Net.Tests/Index/TestBagOfPostings.cs
@@ -1,6 +1,7 @@
 using J2N.Collections.Generic.Extensions;
 using J2N.Threading;
 using Lucene.Net.Documents;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Concurrent;
diff --git a/src/Lucene.Net.Tests/Index/TestConcurrentMergeScheduler.cs b/src/Lucene.Net.Tests/Index/TestConcurrentMergeScheduler.cs
index b69a02e..4f3ae80 100644
--- a/src/Lucene.Net.Tests/Index/TestConcurrentMergeScheduler.cs
+++ b/src/Lucene.Net.Tests/Index/TestConcurrentMergeScheduler.cs
@@ -3,6 +3,7 @@ using Lucene.Net.Attributes;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
diff --git a/src/Lucene.Net.Tests/Index/TestDeletionPolicy.cs b/src/Lucene.Net.Tests/Index/TestDeletionPolicy.cs
index 9f8de66..f353e3b 100644
--- a/src/Lucene.Net.Tests/Index/TestDeletionPolicy.cs
+++ b/src/Lucene.Net.Tests/Index/TestDeletionPolicy.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
diff --git a/src/Lucene.Net.Tests/Index/TestDirectoryReader.cs b/src/Lucene.Net.Tests/Index/TestDirectoryReader.cs
index 5c0aa8b..42e6626 100644
--- a/src/Lucene.Net.Tests/Index/TestDirectoryReader.cs
+++ b/src/Lucene.Net.Tests/Index/TestDirectoryReader.cs
@@ -10,6 +10,7 @@ using System.Threading;
 using JCG = J2N.Collections.Generic;
 using Assert = Lucene.Net.TestFramework.Assert;
 using Console = Lucene.Net.Util.SystemConsole;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Index
 {
diff --git a/src/Lucene.Net.Tests/Index/TestDirectoryReaderReopen.cs b/src/Lucene.Net.Tests/Index/TestDirectoryReaderReopen.cs
index 1597167..64ca0c8 100644
--- a/src/Lucene.Net.Tests/Index/TestDirectoryReaderReopen.cs
+++ b/src/Lucene.Net.Tests/Index/TestDirectoryReaderReopen.cs
@@ -10,6 +10,7 @@ using System.Threading;
 using JCG = J2N.Collections.Generic;
 using Assert = Lucene.Net.TestFramework.Assert;
 using Console = Lucene.Net.Util.SystemConsole;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Index
 {
@@ -287,9 +288,14 @@ namespace Lucene.Net.Index
                 threads[i].Start();
             }
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
+            {
+                UninterruptableMonitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+            }
+            finally
             {
-                Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+                UninterruptableMonitor.Exit(this);
             }
 
             for (int i = 0; i < n; i++)
@@ -418,9 +424,14 @@ namespace Lucene.Net.Index
                             refreshed.Dispose();
                         }
                     }
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
+                    {
+                        UninterruptableMonitor.Wait(this, TimeSpan.FromMilliseconds(TestUtil.NextInt32(Random, 1, 100)));
+                    }
+                    finally
                     {
-                        Monitor.Wait(this, TimeSpan.FromMilliseconds(TestUtil.NextInt32(Random, 1, 100)));
+                        UninterruptableMonitor.Exit(this);
                     }
                 }
             }
@@ -450,9 +461,14 @@ namespace Lucene.Net.Index
                         TestDirectoryReader.AssertIndexEquals(c.newReader, c.refreshedReader);
                     }
 
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
-                        Monitor.Wait(this, TimeSpan.FromMilliseconds(TestUtil.NextInt32(Random, 1, 100)));
+                        UninterruptableMonitor.Wait(this, TimeSpan.FromMilliseconds(TestUtil.NextInt32(Random, 1, 100)));
+                    }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
                     }
                 }
             }
@@ -520,7 +536,8 @@ namespace Lucene.Net.Index
 
         internal virtual ReaderCouple RefreshReader(DirectoryReader reader, TestReopen test, int modify, bool hasChanges)
         {
-            lock (createReaderMutex)
+            UninterruptableMonitor.Enter(createReaderMutex);
+            try
             {
                 DirectoryReader r = null;
                 if (test != null)
@@ -564,6 +581,10 @@ namespace Lucene.Net.Index
 
                 return new ReaderCouple(r, refreshed);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(createReaderMutex);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs b/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
index 3af2be4..4d28745 100644
--- a/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
+++ b/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
@@ -1,5 +1,6 @@
 using J2N.Threading;
 using J2N.Threading.Atomic;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
 using System;
@@ -381,9 +382,6 @@ namespace Lucene.Net.Index
             {
                 thread.Start();
             }
-
-            // LUCENENET: This was not in Lucene, but was once a part of this class. We may need to put this back if this test misbehaves in the future.
-            //Thread.Sleep(1); // let them start
         }
 
         public static void Join(ThreadJob[] toJoin)
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
index 56ade97..bc1b84e 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
@@ -1338,7 +1338,7 @@ namespace Lucene.Net.Index
                         // Jenkins hits a fail we need to study where the
                         // interrupts struck!
                         Console.WriteLine("TEST: got interrupt");
-                        Console.WriteLine(re.ToString());
+                        Console.WriteLine(GetToStringFrom(re));
 
                         Exception e = re.InnerException;
                         Assert.IsTrue(e is System.Threading.ThreadInterruptedException);
@@ -1355,7 +1355,7 @@ namespace Lucene.Net.Index
                     //    // Jenkins hits a fail we need to study where the
                     //    // interrupts struck!
                     //    Console.WriteLine("TEST: got .NET interrupt");
-                    //    Console.WriteLine(re.ToString());
+                    //    Console.WriteLine(GetToStringFrom(re));
 
                     //    if (finish)
                     //    {
@@ -1365,7 +1365,7 @@ namespace Lucene.Net.Index
                     catch (Exception t) when (t.IsThrowable())
                     {
                         Console.WriteLine("FAILED; unexpected exception");
-                        Console.WriteLine(t.ToString());
+                        Console.WriteLine(GetToStringFrom(t));
                         failed = true;
                         break;
                     }
@@ -1388,7 +1388,6 @@ namespace Lucene.Net.Index
                     // clear interrupt state:
                     try
                     {
-                        UninterruptableMonitor.RestoreInterrupt();
                         Thread.Sleep(0);
                     }
                     catch (Exception ie) when (ie.IsInterruptedException())
@@ -1447,6 +1446,32 @@ namespace Lucene.Net.Index
                     throw RuntimeException.Create(e);
                 }
             }
+
+            // LUCENENET specific - since the lock statement can potentially throw System.Threading.ThreadInterruptedException in .NET,
+            // we need to be vigilant about getting stack trace info from the errors during tests and retry if we get an interrupt exception.
+            /// <summary>
+            /// Safely gets the ToString() of an exception while ignoring any System.Threading.ThreadInterruptedException and retrying.
+            /// </summary>
+            private string GetToStringFrom(Exception exception)
+            {
+                // Clear interrupt state:
+                try
+                {
+                    Thread.Sleep(0);
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    // ignore
+                }
+                try
+                {
+                    return exception.ToString();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    return GetToStringFrom(exception);
+                }
+            }
         }
 
         [Test]
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs
index 7481bb2..8172648 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs
@@ -7,6 +7,7 @@ using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
@@ -982,11 +983,16 @@ namespace Lucene.Net.Index
                 }
                 catch (Exception t) when (t.IsThrowable())
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         Console.WriteLine(Thread.CurrentThread.Name + ": ERROR: hit unexpected exception");
                         Console.WriteLine(t.StackTrace);
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                     Assert.Fail();
                 }
             }
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterMerging.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterMerging.cs
index c14ee52..376f9e8 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterMerging.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterMerging.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
@@ -305,7 +306,8 @@ namespace Lucene.Net.Index
 
             public override void Merge(IndexWriter writer, MergeTrigger trigger, bool newMergesFound)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     while (true)
                     {
@@ -321,6 +323,10 @@ namespace Lucene.Net.Index
                         writer.Merge(merge);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             protected override void Dispose(bool disposing)
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterNRTIsCurrent.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterNRTIsCurrent.cs
index 1befc55..313d14c 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterNRTIsCurrent.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterNRTIsCurrent.cs
@@ -1,5 +1,6 @@
 using J2N.Threading;
 using Lucene.Net.Documents;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
 using System;
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterOnJRECrash.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterOnJRECrash.cs
index 02894c5..74412ba 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterOnJRECrash.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterOnJRECrash.cs
@@ -106,6 +106,7 @@
 //            {
 //                try
 //                {
+//                    UninterruptableMonitor.RestoreInterrupt();
 //                    Thread.Sleep(CrashTime);
 //                }
 //                catch (Exception e) when (e.IsInterruptedException())
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
index 9bd112c..590fb85 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
@@ -4,6 +4,7 @@ using Lucene.Net.Attributes;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
@@ -544,10 +545,15 @@ namespace Lucene.Net.Index
             internal virtual void Handle(Exception t)
             {
                 Console.WriteLine(t.StackTrace);
-                lock (failures)
+                UninterruptableMonitor.Enter(failures);
+                try
                 {
                     failures.Add(t);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(failures);
+                }
             }
 
             internal virtual void LaunchThreads(int numIter)
diff --git a/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs b/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs
index b07e0fe..3a48b69 100644
--- a/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs
+++ b/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs
@@ -2,6 +2,7 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Attributes;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Threading;
diff --git a/src/Lucene.Net.Tests/Index/TestNeverDelete.cs b/src/Lucene.Net.Tests/Index/TestNeverDelete.cs
index e92fc98..3e8864d 100644
--- a/src/Lucene.Net.Tests/Index/TestNeverDelete.cs
+++ b/src/Lucene.Net.Tests/Index/TestNeverDelete.cs
@@ -9,6 +9,7 @@ using System.Threading;
 using JCG = J2N.Collections.Generic;
 using Assert = Lucene.Net.TestFramework.Assert;
 using Console = Lucene.Net.Util.SystemConsole;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Index
 {
diff --git a/src/Lucene.Net.Tests/Index/TestPayloads.cs b/src/Lucene.Net.Tests/Index/TestPayloads.cs
index e0ebb57..aff3c76 100644
--- a/src/Lucene.Net.Tests/Index/TestPayloads.cs
+++ b/src/Lucene.Net.Tests/Index/TestPayloads.cs
@@ -5,6 +5,7 @@ using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
@@ -617,30 +618,45 @@ namespace Lucene.Net.Index
 
             internal virtual byte[] Get()
             {
-                lock (this) // TODO use BlockingCollection / BCL datastructures instead
+                UninterruptableMonitor.Enter(this); // TODO use BlockingCollection / BCL datastructures instead
+                try
                 {
                     var retArray = pool[0];
                     pool.RemoveAt(0);
                     return retArray;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             internal virtual void Release(byte[] b)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     pool.Add(b);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             internal virtual int Count
             {
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         return pool.Count;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
         }
diff --git a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
index ae923a1..963d533 100644
--- a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
+++ b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
@@ -1,6 +1,7 @@
 using J2N.Threading;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
diff --git a/src/Lucene.Net.Tests/Index/TestStressIndexing2.cs b/src/Lucene.Net.Tests/Index/TestStressIndexing2.cs
index d1c2d52..3155662 100644
--- a/src/Lucene.Net.Tests/Index/TestStressIndexing2.cs
+++ b/src/Lucene.Net.Tests/Index/TestStressIndexing2.cs
@@ -7,6 +7,7 @@ using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
@@ -210,10 +211,15 @@ namespace Lucene.Net.Index
             for (int i = 0; i < threads.Length; i++)
             {
                 IndexingThread th = threads[i];
-                lock (th)
+                UninterruptableMonitor.Enter(th);
+                try
                 {
                     docs.PutAll(th.docs);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(th);
+                }
             }
 
             TestUtil.CheckIndex(dir);
@@ -257,10 +263,15 @@ namespace Lucene.Net.Index
             for (int i = 0; i < threads.Length; i++)
             {
                 IndexingThread th = threads[i];
-                lock (th)
+                UninterruptableMonitor.Enter(th);
+                try
                 {
                     docs.PutAll(th.docs);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(th);
+                }
             }
 
             //System.out.println("TEST: checkindex");
@@ -1043,10 +1054,15 @@ namespace Lucene.Net.Index
                     Assert.Fail(e.ToString());
                 }
 
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     int dummy = docs.Count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
     }
diff --git a/src/Lucene.Net.Tests/Index/TestStressNRT.cs b/src/Lucene.Net.Tests/Index/TestStressNRT.cs
index 4574402..b4f1ebd 100644
--- a/src/Lucene.Net.Tests/Index/TestStressNRT.cs
+++ b/src/Lucene.Net.Tests/Index/TestStressNRT.cs
@@ -3,6 +3,7 @@ using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
 using System;
@@ -206,13 +207,18 @@ namespace Lucene.Net.Index
                                 long version;
                                 DirectoryReader oldReader;
 
-                                lock (outerInstance)
+                                UninterruptableMonitor.Enter(outerInstance);
+                                try
                                 {
                                     newCommittedModel = new Dictionary<int, long>(outerInstance.model); // take a snapshot
                                     version = outerInstance.snapshotCount++;
                                     oldReader = outerInstance.reader;
                                     oldReader.IncRef(); // increment the reference since we will use this for reopening
                                 }
+                                finally
+                                {
+                                    UninterruptableMonitor.Exit(outerInstance);
+                                }
 
                                 DirectoryReader newReader;
                                 if (rand.Next(100) < softCommitPercent)
@@ -260,7 +266,8 @@ namespace Lucene.Net.Index
 
                                 oldReader.DecRef();
 
-                                lock (outerInstance)
+                                UninterruptableMonitor.Enter(outerInstance);
+                                try
                                 {
                                     // install the new reader if it's newest (and check the current version since another reader may have already been installed)
                                     //System.out.println(Thread.currentThread().getName() + ": newVersion=" + newReader.getVersion());
@@ -308,6 +315,10 @@ namespace Lucene.Net.Index
                                         newReader.DecRef();
                                     }
                                 }
+                                finally
+                                {
+                                    UninterruptableMonitor.Exit(outerInstance);
+                                }
                             }
                             numCommitting.DecrementAndGet();
                         }
@@ -326,7 +337,8 @@ namespace Lucene.Net.Index
 
                             // We can't concurrently update the same document and retain our invariants of increasing values
                             // since we can't guarantee what order the updates will be executed.
-                            lock (sync)
+                            UninterruptableMonitor.Enter(sync);
+                            try
                             {
                                 long val = outerInstance.model[id];
                                 long nextVal = Math.Abs(val) + 1;
@@ -390,6 +402,10 @@ namespace Lucene.Net.Index
                                     outerInstance.model[id] = nextVal;
                                 }
                             }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(sync);
+                            }
 
                             if (!before)
                             {
@@ -444,12 +460,17 @@ namespace Lucene.Net.Index
 
                         long val;
                         DirectoryReader r;
-                        lock (outerInstance)
+                        UninterruptableMonitor.Enter(outerInstance);
+                        try
                         {
                             val = outerInstance.committedModel[id];
                             r = outerInstance.reader;
                             r.IncRef();
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(outerInstance);
+                        }
 
                         if (Verbose)
                         {
diff --git a/src/Lucene.Net.Tests/Index/TestTransactions.cs b/src/Lucene.Net.Tests/Index/TestTransactions.cs
index cecfd33..eed8a01 100644
--- a/src/Lucene.Net.Tests/Index/TestTransactions.cs
+++ b/src/Lucene.Net.Tests/Index/TestTransactions.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.IO;
@@ -162,7 +163,8 @@ namespace Lucene.Net.Index
                 doFail = true;
                 try
                 {
-                    lock (@lock)
+                    UninterruptableMonitor.Enter(@lock);
+                    try
                     {
                         try
                         {
@@ -188,6 +190,10 @@ namespace Lucene.Net.Index
                         writer1.Commit();
                         writer2.Commit();
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(@lock);
+                    }
                 }
                 finally
                 {
@@ -239,7 +245,8 @@ namespace Lucene.Net.Index
             public override void DoWork()
             {
                 IndexReader r1 = null, r2 = null;
-                lock (@lock)
+                UninterruptableMonitor.Enter(@lock);
+                try
                 {
                     try
                     {
@@ -263,6 +270,10 @@ namespace Lucene.Net.Index
                         return;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(@lock);
+                }
                 if (r1.NumDocs != r2.NumDocs)
                 {
                     throw RuntimeException.Create("doc counts differ: r1=" + r1.NumDocs + " r2=" + r2.NumDocs);
diff --git a/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs b/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
index 441605a..8486cb8 100644
--- a/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
@@ -1,6 +1,7 @@
 using J2N.Threading;
 using J2N.Threading.Atomic;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
@@ -327,10 +328,15 @@ namespace Lucene.Net.Search
 
         private void AddMaxGen(long gen)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 maxGen = Math.Max(gen, maxGen);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void DoSearching(TaskScheduler es, long stopTime)
diff --git a/src/Lucene.Net.Tests/Search/TestMultiThreadTermVectors.cs b/src/Lucene.Net.Tests/Search/TestMultiThreadTermVectors.cs
index b6740b3..3cba904 100644
--- a/src/Lucene.Net.Tests/Search/TestMultiThreadTermVectors.cs
+++ b/src/Lucene.Net.Tests/Search/TestMultiThreadTermVectors.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.IO;
diff --git a/src/Lucene.Net.Tests/Search/TestSearcherManager.cs b/src/Lucene.Net.Tests/Search/TestSearcherManager.cs
index b072646..d26a8c3 100644
--- a/src/Lucene.Net.Tests/Search/TestSearcherManager.cs
+++ b/src/Lucene.Net.Tests/Search/TestSearcherManager.cs
@@ -2,6 +2,7 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Index;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
 using System;
@@ -195,7 +196,8 @@ namespace Lucene.Net.Search
 
             IndexSearcher s = null;
 
-            lock (pastSearchers)
+            UninterruptableMonitor.Enter(pastSearchers);
+            try
             {
                 while (pastSearchers.Count != 0 && Random.NextDouble() < 0.25)
                 {
@@ -216,6 +218,10 @@ namespace Lucene.Net.Search
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(pastSearchers);
+            }
 
             if (s == null)
             {
@@ -223,13 +229,18 @@ namespace Lucene.Net.Search
                 if (s.IndexReader.NumDocs != 0)
                 {
                     long token = lifetimeMGR.Record(s);
-                    lock (pastSearchers)
+                    UninterruptableMonitor.Enter(pastSearchers);
+                    try
                     {
                         if (!pastSearchers.Contains(token))
                         {
                             pastSearchers.Add(token);
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(pastSearchers);
+                    }
                 }
             }
 
diff --git a/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs b/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
index a41d341..9cdea78 100644
--- a/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
+++ b/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
@@ -6,6 +6,7 @@ using Lucene.Net.Documents;
 using Lucene.Net.Index;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
@@ -361,10 +362,15 @@ namespace Lucene.Net.Search
                 {
                     outerInstance.DoTestSearch();
                 }
-                lock (success)
+                UninterruptableMonitor.Enter(success);
+                try
                 {
                     success.Set(num);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(success);
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests/Store/TestLockFactory.cs b/src/Lucene.Net.Tests/Store/TestLockFactory.cs
index e3e0e22..80278aa 100644
--- a/src/Lucene.Net.Tests/Store/TestLockFactory.cs
+++ b/src/Lucene.Net.Tests/Store/TestLockFactory.cs
@@ -1,6 +1,7 @@
 using J2N.Threading;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Collections.Generic;
diff --git a/src/Lucene.Net.Tests/TestWorstCaseTestBehavior.cs b/src/Lucene.Net.Tests/TestWorstCaseTestBehavior.cs
index 6259402..db12e91 100644
--- a/src/Lucene.Net.Tests/TestWorstCaseTestBehavior.cs
+++ b/src/Lucene.Net.Tests/TestWorstCaseTestBehavior.cs
@@ -1,4 +1,5 @@
 using J2N.Threading;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
diff --git a/src/Lucene.Net.Tests/Util/TestSetOnce.cs b/src/Lucene.Net.Tests/Util/TestSetOnce.cs
index 1608df5..6ef60bc 100644
--- a/src/Lucene.Net.Tests/Util/TestSetOnce.cs
+++ b/src/Lucene.Net.Tests/Util/TestSetOnce.cs
@@ -1,4 +1,5 @@
 using J2N.Threading;
+using Lucene.Net.Support.Threading;
 using NUnit.Framework;
 using System;
 using System.Globalization;