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:45 UTC

[lucenenet] branch master updated (d7a68e4 -> 3dcffb2)

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

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


    from d7a68e4  Lucene.Net.Index.IndexWriter: Removed call to ThreadJob.Interrupted() which internally calls Thread.Sleep(0) which was causing performance issues and deadlocks during IndexWriter.Dispose()
     new 3144ba7  Removed [Deadlock] attribute from tests that were deadlocking due to extra Thread.Sleep(0) call in IndexWriter.Dispose().
     new b1e0eec  SWEEP: Added Lucene.Net.Util.ThreadInterruptedException and re-throw it in all of the places that Lucene does.
     new dd89a4f  Lucene.Net.Support.Threading: Created UninterruptableMonitor class to handle entering locks without throwing System.Threading.ThreadInterruptedException (which is what happens in Java)
     new 19cb0c1  SWEEP: Lucene.Net: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.
     new 152ffe6  SWEEP: Lucene.Net.TestFramework: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.
     new 7c357e7  SWEEP: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.
     new b5ce511  Lucene.Net.Index.DocumentsWriter::UnlockAllAfterAbortAll() Added missing when clause on catch block
     new 3dcffb2  Lucene.Net.Tests.Index.TestIndexWriter: Removed [AwaitsFix] attribute from TestThreadInterruptDeadlock() and TestTwoThreadsInterruptDeadlock(), since they now are passing

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../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            |  79 ++-
 .../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     |  27 +-
 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 +-
 .../Analysis/BaseTokenStreamTestCase.cs            |   1 +
 .../Analysis/MockAnalyzer.cs                       |   8 +-
 .../Codecs/RAMOnly/RAMOnlyPostingsFormat.cs        |  17 +-
 .../Index/BaseDocValuesFormatTestCase.cs           |   1 +
 .../Index/BaseMergePolicyTestCase.cs               |   8 +-
 .../Index/BasePostingsFormatTestCase.cs            |   7 +-
 .../Index/ThreadedIndexingAndSearchingTestCase.cs  |   1 +
 .../Search/RandomSimilarityProvider.cs             |  15 +-
 .../Search/SearchEquivalenceTestBase.cs            |   7 +-
 .../Store/MockDirectoryWrapper.cs                  | 211 +++++-
 .../Store/SlowClosingMockIndexInputWrapper.cs      |   9 +-
 .../Store/SlowOpeningMockIndexInputWrapper.cs      |   5 +-
 src/Lucene.Net.TestFramework/Util/LineFileDocs.cs  |  36 +-
 .../Util/LuceneTestCase.cs                         |  28 +-
 src/Lucene.Net.TestFramework/Util/TestUtil.cs      |   1 +
 .../Util/ThrottledIndexOutput.cs                   |  14 +-
 .../Analysis/Th/TestThaiAnalyzer.cs                |   1 +
 .../Analysis/Icu/Segmentation/TestICUTokenizer.cs  |   1 +
 .../ByTask/Tasks/CountingSearchTestTask.cs         |   8 +-
 .../SimpleText/TestSimpleTextStoredFieldsFormat.cs |   1 -
 src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs     |  27 +-
 .../Taxonomy/TestSearcherTaxonomyManager.cs        |   1 +
 .../Taxonomy/TestTaxonomyCombined.cs               |   2 +
 .../IndexAndTaxonomyReplicationClientTest.cs       |  11 +-
 .../IndexReplicationClientTest.cs                  |  11 +-
 .../LocalReplicatorTest.cs                         |   1 +
 .../Spell/TestSpellChecker.cs                      |   1 +
 .../Analyzing/AnalyzingInfixSuggesterTest.cs       |   1 +
 src/Lucene.Net.Tests/Index/TestAddIndexes.cs       |  23 +-
 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/TestDocumentsWriterDeleteQueue.cs        |  13 +-
 .../Index/TestDocumentsWriterStallControl.cs       |   8 +-
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs      |  71 +-
 .../Index/TestIndexWriterExceptions.cs             |   9 +-
 .../Index/TestIndexWriterMerging.cs                |   8 +-
 .../Index/TestIndexWriterNRTIsCurrent.cs           |   1 +
 .../Index/TestIndexWriterOnJRECrash.cs             |   1 +
 .../Index/TestIndexWriterReader.cs                 |  23 +-
 .../Index/TestIndexWriterWithThreads.cs            |  11 +-
 .../Index/TestNRTReaderWithThreads.cs              |   2 +-
 src/Lucene.Net.Tests/Index/TestNeverDelete.cs      |   1 +
 src/Lucene.Net.Tests/Index/TestPayloads.cs         |  22 +-
 .../Index/TestSnapshotDeletionPolicy.cs            |  12 +-
 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   |  22 +-
 .../Search/TestMultiThreadTermVectors.cs           |   1 +
 src/Lucene.Net.Tests/Search/TestSearcherManager.cs |  15 +-
 .../Search/TestTimeLimitingCollector.cs            |  20 +-
 src/Lucene.Net.Tests/Store/TestLockFactory.cs      |   1 +
 .../ExceptionHandling/TestExceptionExtensions.cs   |   2 +-
 .../Threading/TestUninterruptableMonitor.cs        | 313 +++++++++
 src/Lucene.Net.Tests/TestWorstCaseTestBehavior.cs  |   1 +
 src/Lucene.Net.Tests/Util/TestSetOnce.cs           |   1 +
 src/Lucene.Net/Codecs/Lucene3x/Lucene3xFields.cs   |   8 +-
 .../Codecs/Lucene3x/Lucene3xNormsProducer.cs       |  15 +-
 .../Codecs/Lucene40/Lucene40DocValuesReader.cs     |  22 +-
 .../Codecs/Lucene42/Lucene42DocValuesProducer.cs   |  29 +-
 .../Codecs/Lucene45/Lucene45DocValuesProducer.cs   |  22 +-
 src/Lucene.Net/Index/BufferedUpdatesStream.cs      |  57 +-
 src/Lucene.Net/Index/ConcurrentMergeScheduler.cs   | 130 +++-
 src/Lucene.Net/Index/DocumentsWriter.cs            |  68 +-
 .../Index/DocumentsWriterFlushControl.cs           | 171 ++++-
 src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs  |  59 +-
 .../Index/DocumentsWriterPerThreadPool.cs          |  40 +-
 .../Index/DocumentsWriterStallControl.cs           |  62 +-
 src/Lucene.Net/Index/FieldInfos.cs                 |  36 +-
 src/Lucene.Net/Index/FlushPolicy.cs                |   8 +-
 src/Lucene.Net/Index/IndexFileDeleter.cs           |   5 +-
 src/Lucene.Net/Index/IndexReader.cs                |  32 +-
 src/Lucene.Net/Index/IndexWriter.cs                | 773 +++++++++++++++++----
 src/Lucene.Net/Index/MergePolicy.cs                |  56 +-
 src/Lucene.Net/Index/MultiReader.cs                |  10 +-
 src/Lucene.Net/Index/ParallelAtomicReader.cs       |   8 +-
 src/Lucene.Net/Index/ParallelCompositeReader.cs    |   8 +-
 .../Index/PersistentSnapshotDeletionPolicy.cs      |  43 +-
 src/Lucene.Net/Index/ReadersAndUpdates.cs          | 127 +++-
 src/Lucene.Net/Index/SegmentCoreReaders.cs         |  10 +-
 src/Lucene.Net/Index/SegmentDocValues.cs           |  22 +-
 src/Lucene.Net/Index/SerialMergeScheduler.cs       |   8 +-
 src/Lucene.Net/Index/SlowCompositeReaderWrapper.cs |  17 +-
 src/Lucene.Net/Index/SnapshotDeletionPolicy.cs     |  71 +-
 src/Lucene.Net/Index/StoredFieldsProcessor.cs      |  10 +-
 src/Lucene.Net/Index/TermsEnum.cs                  |  10 +-
 src/Lucene.Net/Search/CachingWrapperFilter.cs      |  10 +-
 .../Search/ControlledRealTimeReopenThread.cs       |  46 +-
 src/Lucene.Net/Search/FieldCacheImpl.cs            |  66 +-
 src/Lucene.Net/Search/IndexSearcher.cs             |   3 +-
 src/Lucene.Net/Search/ReferenceManager.cs          |  14 +-
 src/Lucene.Net/Search/SearcherLifetimeManager.cs   |  22 +-
 src/Lucene.Net/Search/TimeLimitingCollector.cs     |  11 +-
 src/Lucene.Net/Store/CompoundFileDirectory.cs      |  15 +-
 src/Lucene.Net/Store/CompoundFileWriter.cs         |   8 +-
 src/Lucene.Net/Store/Lock.cs                       |  13 +-
 src/Lucene.Net/Store/LockVerifyServer.cs           |   8 +-
 src/Lucene.Net/Store/NRTCachingDirectory.cs        |  57 +-
 src/Lucene.Net/Store/NativeFSLockFactory.cs        | 109 ++-
 src/Lucene.Net/Store/RAMFile.cs                    |  43 +-
 src/Lucene.Net/Store/RateLimiter.cs                |  11 +-
 src/Lucene.Net/Store/SimpleFSDirectory.cs          |   8 +-
 src/Lucene.Net/Store/SingleInstanceLockFactory.cs  |  29 +-
 src/Lucene.Net/Store/VerifyingLockFactory.cs       |  36 +-
 .../Support/Codecs/DefaultCodecFactory.cs          |  24 +-
 .../Codecs/DefaultDocValuesFormatFactory.cs        |  24 +-
 .../Support/Codecs/DefaultPostingsFormatFactory.cs |  24 +-
 src/Lucene.Net/Support/ConcurrentHashSet.cs        |  17 +-
 src/Lucene.Net/Support/ConcurrentSet.cs            | 193 ++++-
 .../ExceptionHandling/ExceptionExtensions.cs       |  10 +-
 src/Lucene.Net/Support/IO/StreamExtensions.cs      |   8 +-
 .../LimitedConcurrencyLevelTaskScheduler.cs        |  30 +-
 src/Lucene.Net/Support/Threading/ReentrantLock.cs  |   8 +-
 .../Support/Threading/UninterruptableMonitor.cs    | 167 +++++
 src/Lucene.Net/Util/AttributeSource.cs             |   8 +-
 src/Lucene.Net/Util/Fst/Util.cs                    |  15 +-
 src/Lucene.Net/Util/InfoStream.cs                  |  15 +-
 .../Util/ThreadInterruptedException.cs}            |  28 +-
 171 files changed, 4395 insertions(+), 757 deletions(-)
 create mode 100644 src/Lucene.Net.Tests/Support/Threading/TestUninterruptableMonitor.cs
 create mode 100644 src/Lucene.Net/Support/Threading/UninterruptableMonitor.cs
 copy src/{Lucene.Net.QueryParser/Xml/ParserException.cs => Lucene.Net/Util/ThreadInterruptedException.cs} (64%)

[lucenenet] 01/08: Removed [Deadlock] attribute from tests that were deadlocking due to extra Thread.Sleep(0) call in IndexWriter.Dispose().

Posted by ni...@apache.org.
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 3144ba76a7866526533ee8b89e5cf26207a18ca6
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Sun Oct 10 06:44:10 2021 +0700

    Removed [Deadlock] attribute from tests that were deadlocking due to extra Thread.Sleep(0) call in IndexWriter.Dispose().
---
 .../SimpleText/TestSimpleTextStoredFieldsFormat.cs                  | 1 -
 src/Lucene.Net.Tests/Index/TestAddIndexes.cs                        | 1 -
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs                       | 6 ++----
 src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs             | 1 -
 src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs                 | 1 -
 src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs            | 1 -
 src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs              | 1 -
 7 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/src/Lucene.Net.Tests.Codecs/SimpleText/TestSimpleTextStoredFieldsFormat.cs b/src/Lucene.Net.Tests.Codecs/SimpleText/TestSimpleTextStoredFieldsFormat.cs
index 5f44527..2f3a765 100644
--- a/src/Lucene.Net.Tests.Codecs/SimpleText/TestSimpleTextStoredFieldsFormat.cs
+++ b/src/Lucene.Net.Tests.Codecs/SimpleText/TestSimpleTextStoredFieldsFormat.cs
@@ -30,7 +30,6 @@ namespace Lucene.Net.Codecs.SimpleText
         }
 
 
-        [Deadlock][Timeout(600000)]
         public override void TestConcurrentReads()
         {
             base.TestConcurrentReads();
diff --git a/src/Lucene.Net.Tests/Index/TestAddIndexes.cs b/src/Lucene.Net.Tests/Index/TestAddIndexes.cs
index 526d1b9..a44c384 100644
--- a/src/Lucene.Net.Tests/Index/TestAddIndexes.cs
+++ b/src/Lucene.Net.Tests/Index/TestAddIndexes.cs
@@ -972,7 +972,6 @@ namespace Lucene.Net.Index
         // LUCENE-1335: test simultaneous addIndexes & close
         [Test]
         [Slow]
-        [Deadlock][Timeout(600000)]
         public virtual void TestAddIndexesWithCloseNoWait()
         {
             const int NUM_COPY = 50;
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
index 22f2baa..05f1b09 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
@@ -1438,8 +1438,7 @@ namespace Lucene.Net.Index
 
         [Test]
         [Slow]
-        [AwaitsFix(BugUrl = "https://github.com/apache/lucenenet/issues/269")] // LUCENENET TODO: this test occasionally fails
-        [Deadlock][Timeout(900000)] // LUCENENET TODO: this test occasionally deadlocks
+        [AwaitsFix(BugUrl = "https://github.com/apache/lucenenet/issues/269")] // LUCENENET TODO: this test occasionally fails on .NET Core
         public virtual void TestThreadInterruptDeadlock()
         {
             IndexerThreadInterrupt t = new IndexerThreadInterrupt(this);
@@ -1480,8 +1479,7 @@ namespace Lucene.Net.Index
         /// testThreadInterruptDeadlock but with 2 indexer threads </summary>
         [Test]
         [Slow]
-        [AwaitsFix(BugUrl = "https://github.com/apache/lucenenet/issues/269")] // LUCENENET TODO: this test occasionally fails
-        [Deadlock][Timeout(900000)] // LUCENENET TODO: this test occasionally deadlocks
+        [AwaitsFix(BugUrl = "https://github.com/apache/lucenenet/issues/269")] // LUCENENET TODO: this test occasionally fails on .NET Core
         public virtual void TestTwoThreadsInterruptDeadlock()
         {
             IndexerThreadInterrupt t1 = new IndexerThreadInterrupt(this);
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs
index 5d774c3..7481bb2 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterExceptions.cs
@@ -69,7 +69,6 @@ namespace Lucene.Net.Index
     using TokenStream = Lucene.Net.Analysis.TokenStream;
 
     [TestFixture]
-    [Deadlock][Timeout(600000)]
     public class TestIndexWriterExceptions : LuceneTestCase
     {
         private class DocCopyIterator : IEnumerable<Document>
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
index da3a07f..b000cf5 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
@@ -52,7 +52,6 @@ namespace Lucene.Net.Index
     using TopDocs = Lucene.Net.Search.TopDocs;
 
     [TestFixture]
-    [Deadlock][Timeout(600000)]
     public class TestIndexWriterReader : LuceneTestCase
     {
         private readonly int numThreads = TestNightly ? 5 : 3;
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
index 11c2d95..f9b0a71 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
@@ -55,7 +55,6 @@ namespace Lucene.Net.Index
     /// </summary>
     [SuppressCodecs("Lucene3x")]
     [Slow]
-    [Deadlock][Timeout(1200000)]
     [TestFixture]
     public class TestIndexWriterWithThreads : LuceneTestCase
     {
diff --git a/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs b/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs
index 183f87e..b07e0fe 100644
--- a/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs
+++ b/src/Lucene.Net.Tests/Index/TestNRTReaderWithThreads.cs
@@ -39,7 +39,6 @@ namespace Lucene.Net.Index
 
         [Test]
         [Slow] // (occasionally)
-        [Deadlock][Timeout(600000)]
         public virtual void TestIndexing()
         {
             Directory mainDir = NewDirectory();

[lucenenet] 07/08: Lucene.Net.Index.DocumentsWriter::UnlockAllAfterAbortAll() Added missing when clause on catch block

Posted by ni...@apache.org.
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 b5ce511047d5815165b7f454aa00382f0cf7abd6
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Sat Oct 16 20:44:39 2021 +0700

    Lucene.Net.Index.DocumentsWriter::UnlockAllAfterAbortAll() Added missing when clause on catch block
---
 src/Lucene.Net/Index/DocumentsWriter.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Lucene.Net/Index/DocumentsWriter.cs b/src/Lucene.Net/Index/DocumentsWriter.cs
index a1745bf..61c26a4 100644
--- a/src/Lucene.Net/Index/DocumentsWriter.cs
+++ b/src/Lucene.Net/Index/DocumentsWriter.cs
@@ -406,7 +406,7 @@ namespace Lucene.Net.Index
                             perThread.Unlock();
                         }
                     }
-                    catch (Exception e)
+                    catch (Exception e) when (e.IsThrowable())
                     {
                         if (infoStream.IsEnabled("DW"))
                         {

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

Posted by ni...@apache.org.
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 19cb0c1d806462aad2b6297e0885491062887456
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Thu Oct 14 20:41:49 2021 +0700

    SWEEP: Lucene.Net: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.
---
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs      |   2 +
 src/Lucene.Net/Codecs/Lucene3x/Lucene3xFields.cs   |   8 +-
 .../Codecs/Lucene3x/Lucene3xNormsProducer.cs       |  15 +-
 .../Codecs/Lucene40/Lucene40DocValuesReader.cs     |  22 +-
 .../Codecs/Lucene42/Lucene42DocValuesProducer.cs   |  29 +-
 .../Codecs/Lucene45/Lucene45DocValuesProducer.cs   |  22 +-
 src/Lucene.Net/Index/BufferedUpdatesStream.cs      |  57 +-
 src/Lucene.Net/Index/ConcurrentMergeScheduler.cs   | 100 ++-
 src/Lucene.Net/Index/DocumentsWriter.cs            |  66 +-
 .../Index/DocumentsWriterFlushControl.cs           | 163 ++++-
 src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs  |  59 +-
 .../Index/DocumentsWriterPerThreadPool.cs          |  32 +-
 .../Index/DocumentsWriterStallControl.cs           |  40 +-
 src/Lucene.Net/Index/FieldInfos.cs                 |  36 +-
 src/Lucene.Net/Index/FlushPolicy.cs                |   8 +-
 src/Lucene.Net/Index/IndexFileDeleter.cs           |   5 +-
 src/Lucene.Net/Index/IndexReader.cs                |  32 +-
 src/Lucene.Net/Index/IndexWriter.cs                | 756 +++++++++++++++++----
 src/Lucene.Net/Index/MergePolicy.cs                |  56 +-
 src/Lucene.Net/Index/MultiReader.cs                |  10 +-
 src/Lucene.Net/Index/ParallelAtomicReader.cs       |   8 +-
 src/Lucene.Net/Index/ParallelCompositeReader.cs    |   8 +-
 .../Index/PersistentSnapshotDeletionPolicy.cs      |  43 +-
 src/Lucene.Net/Index/ReadersAndUpdates.cs          | 127 +++-
 src/Lucene.Net/Index/SegmentCoreReaders.cs         |  10 +-
 src/Lucene.Net/Index/SegmentDocValues.cs           |  22 +-
 src/Lucene.Net/Index/SerialMergeScheduler.cs       |   8 +-
 src/Lucene.Net/Index/SlowCompositeReaderWrapper.cs |  17 +-
 src/Lucene.Net/Index/SnapshotDeletionPolicy.cs     |  71 +-
 src/Lucene.Net/Index/StoredFieldsProcessor.cs      |  10 +-
 src/Lucene.Net/Index/TermsEnum.cs                  |  10 +-
 src/Lucene.Net/Search/CachingWrapperFilter.cs      |  10 +-
 .../Search/ControlledRealTimeReopenThread.cs       |  26 +-
 src/Lucene.Net/Search/FieldCacheImpl.cs            |  66 +-
 src/Lucene.Net/Search/ReferenceManager.cs          |  14 +-
 src/Lucene.Net/Search/SearcherLifetimeManager.cs   |  22 +-
 src/Lucene.Net/Search/TimeLimitingCollector.cs     |   1 +
 src/Lucene.Net/Store/CompoundFileDirectory.cs      |  15 +-
 src/Lucene.Net/Store/CompoundFileWriter.cs         |   8 +-
 src/Lucene.Net/Store/Lock.cs                       |   3 +-
 src/Lucene.Net/Store/LockVerifyServer.cs           |   8 +-
 src/Lucene.Net/Store/NRTCachingDirectory.cs        |  57 +-
 src/Lucene.Net/Store/NativeFSLockFactory.cs        | 109 ++-
 src/Lucene.Net/Store/RAMFile.cs                    |  43 +-
 src/Lucene.Net/Store/RateLimiter.cs                |   1 +
 src/Lucene.Net/Store/SimpleFSDirectory.cs          |   8 +-
 src/Lucene.Net/Store/SingleInstanceLockFactory.cs  |  29 +-
 src/Lucene.Net/Store/VerifyingLockFactory.cs       |  36 +-
 .../Support/Codecs/DefaultCodecFactory.cs          |  24 +-
 .../Codecs/DefaultDocValuesFormatFactory.cs        |  24 +-
 .../Support/Codecs/DefaultPostingsFormatFactory.cs |  24 +-
 src/Lucene.Net/Support/ConcurrentHashSet.cs        |  17 +-
 src/Lucene.Net/Support/ConcurrentSet.cs            | 193 +++++-
 src/Lucene.Net/Support/IO/StreamExtensions.cs      |   8 +-
 .../LimitedConcurrencyLevelTaskScheduler.cs        |  30 +-
 src/Lucene.Net/Support/Threading/ReentrantLock.cs  |   8 +-
 src/Lucene.Net/Util/AttributeSource.cs             |   8 +-
 src/Lucene.Net/Util/Fst/Util.cs                    |  15 +-
 src/Lucene.Net/Util/InfoStream.cs                  |  15 +-
 59 files changed, 2267 insertions(+), 407 deletions(-)

diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
index ce37594..56ade97 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
@@ -10,6 +10,7 @@ using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Search;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using NUnit.Framework;
 using RandomizedTesting.Generators;
@@ -1387,6 +1388,7 @@ namespace Lucene.Net.Index
                     // clear interrupt state:
                     try
                     {
+                        UninterruptableMonitor.RestoreInterrupt();
                         Thread.Sleep(0);
                     }
                     catch (Exception ie) when (ie.IsInterruptedException())
diff --git a/src/Lucene.Net/Codecs/Lucene3x/Lucene3xFields.cs b/src/Lucene.Net/Codecs/Lucene3x/Lucene3xFields.cs
index 68a210d..215d488 100644
--- a/src/Lucene.Net/Codecs/Lucene3x/Lucene3xFields.cs
+++ b/src/Lucene.Net/Codecs/Lucene3x/Lucene3xFields.cs
@@ -1,6 +1,7 @@
 using J2N.Text;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -176,7 +177,8 @@ namespace Lucene.Net.Codecs.Lucene3x
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (Tis != null)
                     {
@@ -187,6 +189,10 @@ namespace Lucene.Net.Codecs.Lucene3x
                         return TisNoIndex;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Codecs/Lucene3x/Lucene3xNormsProducer.cs b/src/Lucene.Net/Codecs/Lucene3x/Lucene3xNormsProducer.cs
index b5e4792..08a3359 100644
--- a/src/Lucene.Net/Codecs/Lucene3x/Lucene3xNormsProducer.cs
+++ b/src/Lucene.Net/Codecs/Lucene3x/Lucene3xNormsProducer.cs
@@ -1,6 +1,7 @@
 using J2N.Runtime.CompilerServices;
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -217,17 +218,23 @@ namespace Lucene.Net.Codecs.Lucene3x
             {
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         if (instance == null)
                         {
                             var bytes = new byte[outerInstance.maxdoc];
                             // some norms share fds
-                            lock (file)
+                            UninterruptableMonitor.Enter(file);
+                            try
                             {
                                 file.Seek(offset);
                                 file.ReadBytes(bytes, 0, bytes.Length, false);
                             }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(file);
+                            }
                             // we are done with this file
                             if (file != outerInstance.singleNormStream)
                             {
@@ -239,6 +246,10 @@ namespace Lucene.Net.Codecs.Lucene3x
                         }
                         return instance;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
diff --git a/src/Lucene.Net/Codecs/Lucene40/Lucene40DocValuesReader.cs b/src/Lucene.Net/Codecs/Lucene40/Lucene40DocValuesReader.cs
index 55b1a7a..d43765d 100644
--- a/src/Lucene.Net/Codecs/Lucene40/Lucene40DocValuesReader.cs
+++ b/src/Lucene.Net/Codecs/Lucene40/Lucene40DocValuesReader.cs
@@ -1,5 +1,6 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -74,7 +75,8 @@ namespace Lucene.Net.Codecs.Lucene40
 
         public override NumericDocValues GetNumeric(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!numericInstances.TryGetValue(field.Number, out NumericDocValues instance))
                 {
@@ -138,6 +140,10 @@ namespace Lucene.Net.Codecs.Lucene40
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -431,7 +437,8 @@ namespace Lucene.Net.Codecs.Lucene40
 
         public override BinaryDocValues GetBinary(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!binaryInstances.TryGetValue(field.Number, out BinaryDocValues instance))
                 {
@@ -461,6 +468,10 @@ namespace Lucene.Net.Codecs.Lucene40
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private BinaryDocValues LoadBytesFixedStraight(FieldInfo field)
@@ -699,7 +710,8 @@ namespace Lucene.Net.Codecs.Lucene40
 
         public override SortedDocValues GetSorted(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!sortedInstances.TryGetValue(field.Number, out SortedDocValues instance))
                 {
@@ -747,6 +759,10 @@ namespace Lucene.Net.Codecs.Lucene40
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private SortedDocValues LoadBytesFixedSorted(/*FieldInfo field, // LUCENENET: Never read */ IndexInput data, IndexInput index)
diff --git a/src/Lucene.Net/Codecs/Lucene42/Lucene42DocValuesProducer.cs b/src/Lucene.Net/Codecs/Lucene42/Lucene42DocValuesProducer.cs
index e7e85dd..7a9df8a 100644
--- a/src/Lucene.Net/Codecs/Lucene42/Lucene42DocValuesProducer.cs
+++ b/src/Lucene.Net/Codecs/Lucene42/Lucene42DocValuesProducer.cs
@@ -1,5 +1,6 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util.Fst;
 using System;
 using System.Collections.Generic;
@@ -222,7 +223,8 @@ namespace Lucene.Net.Codecs.Lucene42
 
         public override NumericDocValues GetNumeric(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!numericInstances.TryGetValue(field.Number, out NumericDocValues instance) || instance == null)
                 {
@@ -231,6 +233,10 @@ namespace Lucene.Net.Codecs.Lucene42
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override long RamBytesUsed() => ramBytesUsed;
@@ -348,7 +354,8 @@ namespace Lucene.Net.Codecs.Lucene42
 
         public override BinaryDocValues GetBinary(FieldInfo field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!binaryInstances.TryGetValue(field.Number, out BinaryDocValues instance) || instance == null)
                 {
@@ -357,6 +364,10 @@ namespace Lucene.Net.Codecs.Lucene42
                 }
                 return instance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private BinaryDocValues LoadBinary(FieldInfo field)
@@ -422,7 +433,8 @@ namespace Lucene.Net.Codecs.Lucene42
         {
             FSTEntry entry = fsts[field.Number];
             FST<long?> instance;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!fstInstances.TryGetValue(field.Number, out instance) || instance == null)
                 {
@@ -432,6 +444,10 @@ namespace Lucene.Net.Codecs.Lucene42
                     fstInstances[field.Number] = instance;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             var docToOrd = GetNumeric(field);
             var fst = instance;
 
@@ -533,7 +549,8 @@ namespace Lucene.Net.Codecs.Lucene42
                 return DocValues.EMPTY_SORTED_SET; // empty FST!
             }
             FST<long?> instance;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!fstInstances.TryGetValue(field.Number, out instance) || instance == null)
                 {
@@ -543,6 +560,10 @@ namespace Lucene.Net.Codecs.Lucene42
                     fstInstances[field.Number] = instance;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             BinaryDocValues docToOrds = GetBinary(field);
             FST<long?> fst = instance;
 
diff --git a/src/Lucene.Net/Codecs/Lucene45/Lucene45DocValuesProducer.cs b/src/Lucene.Net/Codecs/Lucene45/Lucene45DocValuesProducer.cs
index f0f945d..36b9d6a 100644
--- a/src/Lucene.Net/Codecs/Lucene45/Lucene45DocValuesProducer.cs
+++ b/src/Lucene.Net/Codecs/Lucene45/Lucene45DocValuesProducer.cs
@@ -2,6 +2,7 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -507,7 +508,8 @@ namespace Lucene.Net.Codecs.Lucene45
         protected virtual MonotonicBlockPackedReader GetAddressInstance(IndexInput data, FieldInfo field, BinaryEntry bytes)
         {
             MonotonicBlockPackedReader addresses;
-            lock (addressInstances)
+            UninterruptableMonitor.Enter(addressInstances);
+            try
             {
                 if (!addressInstances.TryGetValue(field.Number, out MonotonicBlockPackedReader addrInstance) || addrInstance == null)
                 {
@@ -518,6 +520,10 @@ namespace Lucene.Net.Codecs.Lucene45
                 }
                 addresses = addrInstance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(addressInstances);
+            }
             return addresses;
         }
 
@@ -576,7 +582,8 @@ namespace Lucene.Net.Codecs.Lucene45
         {
             MonotonicBlockPackedReader addresses;
             long interval = bytes.AddressInterval;
-            lock (addressInstances)
+            UninterruptableMonitor.Enter(addressInstances);
+            try
             {
                 if (!addressInstances.TryGetValue(field.Number, out MonotonicBlockPackedReader addrInstance))
                 {
@@ -596,6 +603,10 @@ namespace Lucene.Net.Codecs.Lucene45
                 }
                 addresses = addrInstance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(addressInstances);
+            }
             return addresses;
         }
 
@@ -683,7 +694,8 @@ namespace Lucene.Net.Codecs.Lucene45
         protected virtual MonotonicBlockPackedReader GetOrdIndexInstance(IndexInput data, FieldInfo field, NumericEntry entry)
         {
             MonotonicBlockPackedReader ordIndex;
-            lock (ordIndexInstances)
+            UninterruptableMonitor.Enter(ordIndexInstances);
+            try
             {
                 if (!ordIndexInstances.TryGetValue(field.Number, out MonotonicBlockPackedReader ordIndexInstance))
                 {
@@ -694,6 +706,10 @@ namespace Lucene.Net.Codecs.Lucene45
                 }
                 ordIndex = ordIndexInstance;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(ordIndexInstances);
+            }
             return ordIndex;
         }
 
diff --git a/src/Lucene.Net/Index/BufferedUpdatesStream.cs b/src/Lucene.Net/Index/BufferedUpdatesStream.cs
index 526586b..3139391 100644
--- a/src/Lucene.Net/Index/BufferedUpdatesStream.cs
+++ b/src/Lucene.Net/Index/BufferedUpdatesStream.cs
@@ -1,6 +1,7 @@
 using J2N.Text;
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -78,7 +79,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual long Push(FrozenBufferedUpdates packet)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 /*
                  * The insert operation must be atomic. If we let threads increment the gen
@@ -105,17 +107,26 @@ namespace Lucene.Net.Index
                 if (Debugging.AssertsEnabled) Debugging.Assert(CheckDeleteStats());
                 return packet.DelGen;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void Clear()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 updates.Clear();
                 nextGen = 1;
                 numTerms.Value = 0;
                 bytesUsed.Value = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual bool Any() => bytesUsed != 0;
@@ -169,7 +180,8 @@ namespace Lucene.Net.Index
         [MethodImpl(MethodImplOptions.NoInlining)]
         public virtual ApplyDeletesResult ApplyDeletesAndUpdates(IndexWriter.ReaderPool readerPool, IList<SegmentCommitInfo> infos)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 long t0 = J2N.Time.NanoTime() / J2N.Time.MillisecondsPerNanosecond; // LUCENENET: Use NanoTime() rather than CurrentTimeMilliseconds() for more accurate/reliable results
 
@@ -371,14 +383,23 @@ namespace Lucene.Net.Index
 
                 return new ApplyDeletesResult(anyNewDeletes, gen, allDeleted);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual long GetNextGen()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return nextGen++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // Lock order IW -> BD
@@ -390,7 +411,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual void Prune(SegmentInfos segmentInfos)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(CheckDeleteStats());
                 long minGen = long.MaxValue;
@@ -422,11 +444,16 @@ namespace Lucene.Net.Index
                     Debugging.Assert(CheckDeleteStats());
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void Prune(int count)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (count > 0)
                 {
@@ -445,12 +472,17 @@ namespace Lucene.Net.Index
                     updates.RemoveRange(0, count); // LUCENENET: Checked count parameter for correctness
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // Delete by Term
         private long ApplyTermDeletes(IEnumerable<Term> termsIter, ReadersAndUpdates rld, SegmentReader reader)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 long delCount = 0;
                 Fields fields = reader.Fields;
@@ -535,12 +567,17 @@ namespace Lucene.Net.Index
 
                 return delCount;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // DocValues updates
         private void ApplyDocValuesUpdates<T1>(IEnumerable<T1> updates, ReadersAndUpdates rld, SegmentReader reader, DocValuesFieldUpdates.Container dvUpdatesContainer) where T1 : DocValuesUpdate
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Fields fields = reader.Fields;
                 if (fields == null)
@@ -627,6 +664,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public class QueryAndLimit
diff --git a/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs b/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
index 16c3b00..c653b42 100644
--- a/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
+++ b/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
@@ -1,5 +1,6 @@
 using J2N.Threading;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
@@ -149,11 +150,16 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     InitMergeThreadPriority();
                     return mergeThreadPriority;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -167,7 +173,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual void SetMergeThreadPriority(int priority)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (priority > (int)ThreadPriority.Highest || priority < (int)ThreadPriority.Lowest)
                 {
@@ -176,6 +183,10 @@ namespace Lucene.Net.Index
                 mergeThreadPriority = priority;
                 UpdateMergeThreads();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -199,7 +210,8 @@ namespace Lucene.Net.Index
         /// </summary>
         protected virtual void UpdateMergeThreads()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // Only look at threads that are alive & not in the
                 // process of stopping (ie have an active merge):
@@ -269,6 +281,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -295,7 +311,8 @@ namespace Lucene.Net.Index
 
         private void InitMergeThreadPriority()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (mergeThreadPriority == -1)
                 {
@@ -308,6 +325,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void Dispose(bool disposing)
@@ -325,7 +346,8 @@ namespace Lucene.Net.Index
                 while (true)
                 {
                     MergeThread toSync = null;
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         foreach (MergeThread t in m_mergeThreads)
                         {
@@ -336,6 +358,10 @@ namespace Lucene.Net.Index
                             }
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                     if (toSync != null)
                     {
                         try
@@ -372,7 +398,8 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     int count = 0;
                     foreach (MergeThread mt in m_mergeThreads)
@@ -384,15 +411,20 @@ namespace Lucene.Net.Index
                     }
                     return count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)]
         public override void Merge(IndexWriter writer, MergeTrigger trigger, bool newMergesFound)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
-                if (Debugging.AssertsEnabled) Debugging.Assert(!Monitor.IsEntered(writer));
+                if (Debugging.AssertsEnabled) Debugging.Assert(!UninterruptableMonitor.IsEntered(writer));
 
                 this.m_writer = writer;
 
@@ -436,7 +468,7 @@ namespace Lucene.Net.Index
                         }
                         try
                         {
-                            Monitor.Wait(this);
+                            UninterruptableMonitor.Wait(this);
                         }
                         catch (Exception ie) when (ie.IsInterruptedException())
                         {
@@ -497,6 +529,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -511,7 +547,8 @@ namespace Lucene.Net.Index
         /// Create and return a new <see cref="MergeThread"/> </summary>
         protected virtual MergeThread GetMergeThread(IndexWriter writer, MergePolicy.OneMerge merge)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MergeThread thread = new MergeThread(this, writer, merge);
                 thread.SetThreadPriority((ThreadPriority)mergeThreadPriority);
@@ -519,6 +556,10 @@ namespace Lucene.Net.Index
                 thread.Name = "Lucene Merge Thread #" + m_mergeThreadCount++;
                 return thread;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -549,17 +590,27 @@ namespace Lucene.Net.Index
             {
                 set
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         runningMerge = value;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         return runningMerge;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
@@ -571,7 +622,8 @@ namespace Lucene.Net.Index
             {
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         if (done)
                         {
@@ -586,6 +638,10 @@ namespace Lucene.Net.Index
                             return startMerge;
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
@@ -639,9 +695,14 @@ namespace Lucene.Net.Index
                         // Notify here in case any threads were stalled;
                         // they will notice that the pending merge has
                         // been pulled and possibly resume:
-                        lock (outerInstance)
+                        UninterruptableMonitor.Enter(outerInstance);
+                        try
                         {
-                            Monitor.PulseAll(outerInstance);
+                            UninterruptableMonitor.PulseAll(outerInstance);
+                        }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(outerInstance);
                         }
 
                         if (merge != null)
@@ -681,10 +742,15 @@ namespace Lucene.Net.Index
                 finally
                 {
                     done = true;
-                    lock (outerInstance)
+                    UninterruptableMonitor.Enter(outerInstance);
+                    try
                     {
                         outerInstance.UpdateMergeThreads();
-                        Monitor.PulseAll(outerInstance);
+                        UninterruptableMonitor.PulseAll(outerInstance);
+                    }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(outerInstance);
                     }
                 }
             }
diff --git a/src/Lucene.Net/Index/DocumentsWriter.cs b/src/Lucene.Net/Index/DocumentsWriter.cs
index 2bbde15..a1745bf 100644
--- a/src/Lucene.Net/Index/DocumentsWriter.cs
+++ b/src/Lucene.Net/Index/DocumentsWriter.cs
@@ -1,5 +1,6 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -146,7 +147,8 @@ namespace Lucene.Net.Index
 
         internal bool DeleteQueries(params Query[] queries)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // TODO why is this synchronized?
                 DocumentsWriterDeleteQueue deleteQueue = this.deleteQueue;
@@ -154,6 +156,10 @@ namespace Lucene.Net.Index
                 flushControl.DoOnDelete();
                 return ApplyAllDeletes(deleteQueue);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // TODO: we could check w/ FreqProxTermsWriter: if the
@@ -161,7 +167,8 @@ namespace Lucene.Net.Index
         // per-DWPT map (but still must go into the global map)
         internal bool DeleteTerms(params Term[] terms)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // TODO why is this synchronized?
                 DocumentsWriterDeleteQueue deleteQueue = this.deleteQueue;
@@ -169,28 +176,42 @@ namespace Lucene.Net.Index
                 flushControl.DoOnDelete();
                 return ApplyAllDeletes(deleteQueue);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal bool UpdateNumericDocValue(Term term, string field, long? value)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 DocumentsWriterDeleteQueue deleteQueue = this.deleteQueue;
                 deleteQueue.AddNumericUpdate(new NumericDocValuesUpdate(term, field, value));
                 flushControl.DoOnDelete();
                 return ApplyAllDeletes(deleteQueue);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal bool UpdateBinaryDocValue(Term term, string field, BytesRef value)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 DocumentsWriterDeleteQueue deleteQueue = this.deleteQueue;
                 deleteQueue.AddBinaryUpdate(new BinaryDocValuesUpdate(term, field, value));
                 flushControl.DoOnDelete();
                 return ApplyAllDeletes(deleteQueue);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal DocumentsWriterDeleteQueue CurrentDeleteSession => deleteQueue;
@@ -242,9 +263,10 @@ namespace Lucene.Net.Index
         [MethodImpl(MethodImplOptions.NoInlining)]
         internal void Abort(IndexWriter writer)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
-                if (Debugging.AssertsEnabled) Debugging.Assert(!Monitor.IsEntered(writer), "IndexWriter lock should never be hold when aborting");
+                if (Debugging.AssertsEnabled) Debugging.Assert(!UninterruptableMonitor.IsEntered(writer), "IndexWriter lock should never be hold when aborting");
                 bool success = false;
                 JCG.HashSet<string> newFilesSet = new JCG.HashSet<string>();
                 try
@@ -281,11 +303,16 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal void LockAndAbortAll(IndexWriter indexWriter)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(indexWriter.HoldsFullFlushLock);
                 if (infoStream.IsEnabled("DW"))
@@ -323,6 +350,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void AbortThreadState(ThreadState perThread, ISet<string> newFiles)
@@ -356,7 +387,8 @@ namespace Lucene.Net.Index
 
         internal void UnlockAllAfterAbortAll(IndexWriter indexWriter)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(indexWriter.HoldsFullFlushLock);
                 if (infoStream.IsEnabled("DW"))
@@ -384,6 +416,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal bool AnyChanges()
@@ -708,11 +744,16 @@ namespace Lucene.Net.Index
         // for asserts
         private bool SetFlushingDeleteQueue(DocumentsWriterDeleteQueue session)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 currentFullFlushDelQueue = session;
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /*
@@ -729,7 +770,8 @@ namespace Lucene.Net.Index
                 infoStream.Message("DW", "startFullFlush");
             }
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 pendingChangesInCurrentFullFlush = AnyChanges();
                 flushingDeleteQueue = deleteQueue;
@@ -739,6 +781,10 @@ namespace Lucene.Net.Index
                 flushControl.MarkForFullFlush(); // swaps the delQueue synced on FlushControl
                 if (Debugging.AssertsEnabled) Debugging.Assert(SetFlushingDeleteQueue(flushingDeleteQueue));
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             if (Debugging.AssertsEnabled)
             {
                 Debugging.Assert(currentFullFlushDelQueue != null);
diff --git a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
index 124f8b7..f854ab0 100644
--- a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
@@ -1,6 +1,7 @@
 using J2N.Runtime.CompilerServices;
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -86,10 +87,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return activeBytes;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -97,10 +103,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return flushBytes;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -108,10 +119,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return flushBytes + activeBytes;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -195,7 +211,8 @@ namespace Lucene.Net.Index
 
         internal DocumentsWriterPerThread DoAfterDocument(ThreadState perThread, bool isUpdate)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 try
                 {
@@ -242,6 +259,10 @@ namespace Lucene.Net.Index
                     if (Debugging.AssertsEnabled) Debugging.Assert(AssertNumDocsSinceStalled(stalled) && AssertMemory());
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool AssertNumDocsSinceStalled(bool stalled)
@@ -266,7 +287,8 @@ namespace Lucene.Net.Index
 
         internal void DoAfterFlush(DocumentsWriterPerThread dwpt)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(flushingWriters.ContainsKey(dwpt));
                 try
@@ -285,15 +307,19 @@ namespace Lucene.Net.Index
                     }
                     finally
                     {
-                        Monitor.PulseAll(this);
+                        UninterruptableMonitor.PulseAll(this);
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool UpdateStallState()
         {
-            if (Debugging.AssertsEnabled) Debugging.Assert(Monitor.IsEntered(this));
+            if (Debugging.AssertsEnabled) Debugging.Assert(UninterruptableMonitor.IsEntered(this));
             long limit = StallLimitBytes;
             /*
              * we block indexing threads if net byte grows due to slow flushes
@@ -309,13 +335,14 @@ namespace Lucene.Net.Index
 
         public void WaitForFlush()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 while (flushingWriters.Count != 0)
                 {
                     try
                     {
-                        Monitor.Wait(this);
+                        UninterruptableMonitor.Wait(this);
                     }
                     catch (Exception ie) when (ie.IsInterruptedException())
                     {
@@ -323,6 +350,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -332,7 +363,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public void SetFlushPending(ThreadState perThread)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(!perThread.flushPending);
                 if (perThread.dwpt.NumDocsInRAM > 0)
@@ -345,11 +377,16 @@ namespace Lucene.Net.Index
                     if (Debugging.AssertsEnabled) Debugging.Assert(AssertMemory());
                 } // don't assert on numDocs since we could hit an abort excp. while selecting that dwpt for flushing
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal void DoOnAbort(ThreadState state)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 try
                 {
@@ -370,15 +407,24 @@ namespace Lucene.Net.Index
                     UpdateStallState();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal DocumentsWriterPerThread TryCheckoutForFlush(ThreadState perThread)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(perThread.IsHeldByCurrentThread); // LUCENENET specific: Since .NET Core doesn't use unfair locking, we need to ensure the current thread has a lock before calling InternalTryCheckoutForFlush.
                 return perThread.flushPending ? InternalTryCheckOutForFlush(perThread) : null;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void CheckoutAndBlock(ThreadState perThread)
@@ -409,7 +455,7 @@ namespace Lucene.Net.Index
             {
                 // LUCENENET specific - Since we need to mimic the unfair behavior of ReentrantLock, we need to ensure that all threads that enter here hold the lock.
                 Debugging.Assert(perThread.IsHeldByCurrentThread);
-                Debugging.Assert(Monitor.IsEntered(this));
+                Debugging.Assert(UninterruptableMonitor.IsEntered(this));
                 Debugging.Assert(perThread.flushPending);
             }
             try
@@ -447,7 +493,8 @@ namespace Lucene.Net.Index
         {
             int numPending;
             bool fullFlush;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 DocumentsWriterPerThread poll;
                 if (flushQueue.Count > 0 && (poll = flushQueue.Dequeue()) != null)
@@ -458,6 +505,10 @@ namespace Lucene.Net.Index
                 fullFlush = this.fullFlush;
                 numPending = this.numPending;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             if (numPending > 0 && !fullFlush) // don't check if we are doing a full flush
             {
                 int limit = perThreadPool.NumThreadStatesActive;
@@ -486,7 +537,8 @@ namespace Lucene.Net.Index
 
         internal void SetClosed()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // set by DW to signal that we should not release new DWPT after close
                 if (!closed)
@@ -495,6 +547,10 @@ namespace Lucene.Net.Index
                     perThreadPool.DeactivateUnreleasedStates();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -551,11 +607,16 @@ namespace Lucene.Net.Index
 
         internal void DoOnDelete()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // pass null this is a global delete no update
                 flushPolicy.OnDelete(this, null);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -569,10 +630,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return flushingWriters.Count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -617,7 +683,8 @@ namespace Lucene.Net.Index
         internal void MarkForFullFlush()
         {
             DocumentsWriterDeleteQueue flushingQueue;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled)
                 {
@@ -631,6 +698,10 @@ namespace Lucene.Net.Index
                 DocumentsWriterDeleteQueue newQueue = new DocumentsWriterDeleteQueue(flushingQueue.generation + 1);
                 documentsWriter.deleteQueue = newQueue;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             int limit = perThreadPool.NumThreadStatesActive;
             for (int i = 0; i < limit; i++)
             {
@@ -662,7 +733,8 @@ namespace Lucene.Net.Index
                     next.Unlock();
                 }
             }
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 /* make sure we move all DWPT that are where concurrently marked as
                  * pending and moved to blocked are moved over to the flushQueue. There is
@@ -678,6 +750,10 @@ namespace Lucene.Net.Index
                 fullFlushBuffer.Clear();
                 UpdateStallState();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             if (Debugging.AssertsEnabled) Debugging.Assert(AssertActiveDeleteQueue(documentsWriter.deleteQueue));
         }
 
@@ -718,7 +794,8 @@ namespace Lucene.Net.Index
             }
             if (dwpt.NumDocsInRAM > 0)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (!perThread.flushPending)
                     {
@@ -732,6 +809,10 @@ namespace Lucene.Net.Index
                     }
                     fullFlushBuffer.Add(flushingDWPT);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
             else
             {
@@ -764,7 +845,8 @@ namespace Lucene.Net.Index
 
         internal void FinishFullFlush()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled)
                 {
@@ -787,6 +869,10 @@ namespace Lucene.Net.Index
                     UpdateStallState();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal bool AssertBlockedFlushes(DocumentsWriterDeleteQueue flushingQueue)
@@ -800,7 +886,8 @@ namespace Lucene.Net.Index
 
         internal void AbortFullFlushes(ISet<string> newFiles)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 try
                 {
@@ -811,11 +898,16 @@ namespace Lucene.Net.Index
                     fullFlush = false;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal void AbortPendingFlushes(ISet<string> newFiles)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 try
                 {
@@ -860,6 +952,10 @@ namespace Lucene.Net.Index
                     UpdateStallState();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -869,10 +965,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return fullFlush;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -884,10 +985,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return flushQueue.Count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -900,10 +1006,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return blockedFlushes.Count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs b/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs
index 1c5dd96..6fafb00 100644
--- a/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs
@@ -1,4 +1,4 @@
-using J2N.Threading.Atomic;
+using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
@@ -40,7 +40,8 @@ namespace Lucene.Net.Index
 
         internal virtual void AddDeletes(DocumentsWriterDeleteQueue deleteQueue)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 IncTickets(); // first inc the ticket count - freeze opens
                 // a window for #anyChanges to fail
@@ -58,6 +59,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void IncTickets()
@@ -74,7 +79,8 @@ namespace Lucene.Net.Index
 
         internal virtual SegmentFlushTicket AddFlushTicket(DocumentsWriterPerThread dwpt)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // Each flush is assigned a ticket in the order they acquire the ticketQueue
                 // lock
@@ -96,25 +102,39 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual void AddSegment(SegmentFlushTicket ticket, FlushedSegment segment)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // the actual flush is done asynchronously and once done the FlushedSegment
                 // is passed to the flush ticket
                 ticket.SetSegment(segment);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual void MarkTicketFailed(SegmentFlushTicket ticket)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // to free the queue we mark tickets as failed just to clean up the queue.
                 ticket.SetFailed();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual bool HasTickets
@@ -134,11 +154,16 @@ namespace Lucene.Net.Index
             {
                 FlushTicket head;
                 bool canPublish;
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     head = queue.Count <= 0 ? null : queue.Peek();
                     canPublish = head != null && head.CanPublish; // do this synced
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
                 if (canPublish)
                 {
                     numPurged++;
@@ -154,13 +179,18 @@ namespace Lucene.Net.Index
                     }
                     finally
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             // finally remove the published ticket from the queue
                             FlushTicket poll = queue.Dequeue();
                             ticketCount.DecrementAndGet();
                             if (Debugging.AssertsEnabled) Debugging.Assert(poll == head);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
                 else
@@ -175,8 +205,8 @@ namespace Lucene.Net.Index
         {
             if (Debugging.AssertsEnabled)
             {
-                Debugging.Assert(!Monitor.IsEntered(this));
-                Debugging.Assert(!Monitor.IsEntered(writer));
+                Debugging.Assert(!UninterruptableMonitor.IsEntered(this));
+                Debugging.Assert(!UninterruptableMonitor.IsEntered(writer));
             }
             purgeLock.@Lock();
             try
@@ -193,8 +223,8 @@ namespace Lucene.Net.Index
         {
             if (Debugging.AssertsEnabled)
             {
-                Debugging.Assert(!Monitor.IsEntered(this));
-                Debugging.Assert(!Monitor.IsEntered(writer));
+                Debugging.Assert(!UninterruptableMonitor.IsEntered(this));
+                Debugging.Assert(!UninterruptableMonitor.IsEntered(writer));
             }
             if (purgeLock.TryLock())
             {
@@ -214,11 +244,16 @@ namespace Lucene.Net.Index
 
         internal virtual void Clear()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 queue.Clear();
                 ticketCount.Value = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal abstract class FlushTicket
diff --git a/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs b/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
index 349af3c..1e5af16 100644
--- a/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
@@ -239,7 +239,8 @@ namespace Lucene.Net.Index
 
         private bool AssertUnreleasedThreadStatesInactive()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 for (int i = numThreadStatesActive; i < threadStates.Length; i++)
                 {
@@ -255,6 +256,10 @@ namespace Lucene.Net.Index
                 }
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -262,7 +267,8 @@ namespace Lucene.Net.Index
         /// </summary>
         internal void DeactivateUnreleasedStates()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 for (int i = numThreadStatesActive; i < threadStates.Length; i++)
                 {
@@ -278,6 +284,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal static DocumentsWriterPerThread Reset(ThreadState threadState, bool closed) // LUCENENET: CA1822: Mark members as static
@@ -306,7 +316,8 @@ namespace Lucene.Net.Index
         public ThreadState GetAndLock(/* Thread requestingThread, DocumentsWriter documentsWriter // LUCENENET: Not referenced */)
         {
             ThreadState threadState = null;
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 for (;;)
                 {
@@ -352,7 +363,7 @@ namespace Lucene.Net.Index
                         // Wait until a thread state frees up:
                         try
                         {
-                            Monitor.Wait(this);
+                            UninterruptableMonitor.Wait(this);
                         }
                         catch (Exception ie) when (ie.IsInterruptedException())
                         {
@@ -361,6 +372,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             // This could take time, e.g. if the threadState is [briefly] checked for flushing:
             threadState.Lock();
@@ -371,13 +386,18 @@ namespace Lucene.Net.Index
         public void Release(ThreadState state)
         {
             state.Unlock();
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Debug.Assert(freeCount < freeList.Length);
                 freeList[freeCount++] = state;
                 // In case any thread is waiting, wake one of them up since we just released a thread state; notify() should be sufficient but we do
                 // notifyAll defensively:
-                Monitor.PulseAll(this);
+                UninterruptableMonitor.PulseAll(this);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
             }
         }
 
diff --git a/src/Lucene.Net/Index/DocumentsWriterStallControl.cs b/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
index fad1ab4..3f24887 100644
--- a/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
@@ -1,6 +1,7 @@
 using J2N.Runtime.CompilerServices;
 using J2N.Threading;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -58,14 +59,19 @@ namespace Lucene.Net.Index
         /// </summary>
         internal void UpdateStalled(bool stalled)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 this.stalled = stalled;
                 if (stalled)
                 {
                     wasStalled = true;
                 }
-                Monitor.PulseAll(this);
+                UninterruptableMonitor.PulseAll(this);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
             }
         }
 
@@ -77,7 +83,8 @@ namespace Lucene.Net.Index
         {
             if (stalled)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (stalled) // react on the first wakeup call!
                     {
@@ -88,7 +95,7 @@ namespace Lucene.Net.Index
                             // disabled in production
                             var result = IncWaiters();
                             if (Debugging.AssertsEnabled) Debugging.Assert(result);
-                            Monitor.Wait(this);
+                            UninterruptableMonitor.Wait(this);
                             result = DecrWaiters();
                             if (Debugging.AssertsEnabled) Debugging.Assert(result);
                         }
@@ -98,6 +105,10 @@ namespace Lucene.Net.Index
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -128,10 +139,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return numWaiting > 0;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -139,20 +155,30 @@ namespace Lucene.Net.Index
 
         internal bool IsThreadQueued(ThreadJob t) // for tests
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return waiting.ContainsKey(t);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal bool WasStalled // for tests
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return wasStalled;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
     }
diff --git a/src/Lucene.Net/Index/FieldInfos.cs b/src/Lucene.Net/Index/FieldInfos.cs
index 9283d06..d8d05bd 100644
--- a/src/Lucene.Net/Index/FieldInfos.cs
+++ b/src/Lucene.Net/Index/FieldInfos.cs
@@ -1,5 +1,6 @@
 using J2N.Collections.Generic.Extensions;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -211,7 +212,8 @@ namespace Lucene.Net.Index
             /// </summary>
             internal int AddOrGet(string fieldName, int preferredFieldNumber, DocValuesType dvType)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (dvType != DocValuesType.NONE)
                     {
@@ -249,12 +251,17 @@ namespace Lucene.Net.Index
 
                     return (int)fieldNumber;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             // used by assert
             internal bool ContainsConsistent(int? number, string name, DocValuesType dvType)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     numberToName.TryGetValue(number, out string numberToNameStr);
                     nameToNumber.TryGetValue(name, out int? nameToNumberVal);
@@ -264,6 +271,10 @@ namespace Lucene.Net.Index
                         && number.Equals(nameToNumber[name]) && 
                         (dvType == DocValuesType.NONE || docValuesType == DocValuesType.NONE || dvType == docValuesType);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             /// <summary>
@@ -272,7 +283,8 @@ namespace Lucene.Net.Index
             /// </summary>
             internal bool Contains(string fieldName, DocValuesType dvType)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // used by IndexWriter.updateNumericDocValue
                     if (!nameToNumber.ContainsKey(fieldName))
@@ -286,25 +298,39 @@ namespace Lucene.Net.Index
                         return dvType == dvCand;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             internal void Clear()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     numberToName.Clear();
                     nameToNumber.Clear();
                     docValuesType.Clear();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             internal void SetDocValuesType(int number, string name, DocValuesType dvType)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (Debugging.AssertsEnabled) Debugging.Assert(ContainsConsistent(number, name, dvType));
                     docValuesType[name] = dvType;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Index/FlushPolicy.cs b/src/Lucene.Net/Index/FlushPolicy.cs
index b8c157a..51280b0 100644
--- a/src/Lucene.Net/Index/FlushPolicy.cs
+++ b/src/Lucene.Net/Index/FlushPolicy.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
 
 namespace Lucene.Net.Index
@@ -95,11 +96,16 @@ namespace Lucene.Net.Index
         /// </summary>
         protected internal virtual void Init(LiveIndexWriterConfig indexWriterConfig)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 this.m_indexWriterConfig = indexWriterConfig;
                 m_infoStream = indexWriterConfig.InfoStream;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net/Index/IndexFileDeleter.cs b/src/Lucene.Net/Index/IndexFileDeleter.cs
index 107c250..fa7cd3f 100644
--- a/src/Lucene.Net/Index/IndexFileDeleter.cs
+++ b/src/Lucene.Net/Index/IndexFileDeleter.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -118,7 +119,7 @@ namespace Lucene.Net.Index
 
         // called only from assert
         private bool IsLocked =>
-            writer == null || Monitor.IsEntered(writer);
+            writer == null || UninterruptableMonitor.IsEntered(writer);
 
         /// <summary>
         /// Initialize the deleter: find all previous commits in
@@ -496,7 +497,7 @@ namespace Lucene.Net.Index
             {
                 Debugging.Assert(IsLocked);
 
-                Debugging.Assert(Monitor.IsEntered(writer));
+                Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
             }
             long t0 = 0;
             if (infoStream.IsEnabled("IFD"))
diff --git a/src/Lucene.Net/Index/IndexReader.cs b/src/Lucene.Net/Index/IndexReader.cs
index c75c80b..2e30b45 100644
--- a/src/Lucene.Net/Index/IndexReader.cs
+++ b/src/Lucene.Net/Index/IndexReader.cs
@@ -1,6 +1,7 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Documents;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections;
@@ -145,17 +146,26 @@ namespace Lucene.Net.Index
             EnsureOpen();
             // LUCENENET specific - since neither WeakDictionary nor ConditionalWeakTable synchronize
             // on the enumerator, we need to do external synchronization to make them threadsafe.
-            lock (parentReadersLock)
+            UninterruptableMonitor.Enter(parentReadersLock);
+            try
+            {
                 // LUCENENET: Since there is a set Add operation (unique) in Lucene, the equivalent
                 // operation in .NET is AddOrUpdate, which effectively does nothing if the key exists.
                 // Null is passed as a value, since it is not used anyway and .NET doesn't have a boolean
                 // reference type.
                 parentReaders.AddOrUpdate(key: reader, value: null);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(parentReadersLock);
+            }
         }
 
         private void NotifyReaderClosedListeners(Exception th)
         {
-            lock (((ICollection)readerClosedListeners).SyncRoot) // LUCENENET: Ensure we sync on the SyncRoot of ConcurrentSet<T>
+            object syncRoot = ((ICollection)readerClosedListeners).SyncRoot;
+            UninterruptableMonitor.Enter(syncRoot); // LUCENENET: Ensure we sync on the SyncRoot of ConcurrentSet<T>
+            try
             {
                 foreach (IReaderClosedListener listener in readerClosedListeners)
                 {
@@ -177,13 +187,18 @@ namespace Lucene.Net.Index
                 }
                 IOUtils.ReThrowUnchecked(th);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncRoot);
+            }
         }
 
         private void ReportCloseToParentReaders()
         {
             // LUCENENET specific - since neither WeakDictionary nor ConditionalWeakTable synchronize
             // on the enumerator, we need to do external synchronization to make them threadsafe.
-            lock (parentReadersLock)
+            UninterruptableMonitor.Enter(parentReadersLock);
+            try
             {
                 foreach (var kvp in parentReaders)
                 {
@@ -201,6 +216,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(parentReadersLock);
+            }
         }
 
         /// <summary>
@@ -568,7 +587,8 @@ namespace Lucene.Net.Index
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (!closed)
                     {
@@ -576,6 +596,10 @@ namespace Lucene.Net.Index
                         closed = true;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Index/IndexWriter.cs b/src/Lucene.Net/Index/IndexWriter.cs
index adda7ea..6e320fe 100644
--- a/src/Lucene.Net/Index/IndexWriter.cs
+++ b/src/Lucene.Net/Index/IndexWriter.cs
@@ -4,6 +4,7 @@ using J2N.Threading;
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -372,7 +373,8 @@ namespace Lucene.Net.Index
             bool success2 = false;
             try
             {
-                lock (fullFlushLock)
+                UninterruptableMonitor.Enter(fullFlushLock);
+                try
                 {
                     bool success = false;
                     try
@@ -388,7 +390,8 @@ namespace Lucene.Net.Index
                         // Prevent segmentInfos from changing while opening the
                         // reader; in theory we could instead do similar retry logic,
                         // just like we do when loading segments_N
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             MaybeApplyDeletes(applyAllDeletes);
                             r = StandardDirectoryReader.Open(this, segmentInfos, applyAllDeletes);
@@ -397,6 +400,10 @@ namespace Lucene.Net.Index
                                 infoStream.Message("IW", "return reader version=" + r.Version + " reader=" + r);
                             }
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                     catch (Exception oom) when (oom.IsOutOfMemoryError())
                     {
@@ -419,6 +426,10 @@ namespace Lucene.Net.Index
                         DoAfterFlush();
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(fullFlushLock);
+                }
                 if (anySegmentFlushed)
                 {
                     MaybeMerge(MergeTrigger.FULL_FLUSH, UNBOUNDED_MAX_MERGE_SEGMENTS);
@@ -467,18 +478,24 @@ namespace Lucene.Net.Index
             // used only by asserts
             public virtual bool InfoIsLive(SegmentCommitInfo info)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     int idx = outerInstance.segmentInfos.IndexOf(info);
                     Debugging.Assert(idx != -1, "info={0} isn't live", info);
                     Debugging.Assert(outerInstance.segmentInfos.Info(idx) == info, "info={0} doesn't match live info in segmentInfos", info);
                     return true;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             public virtual void Drop(SegmentCommitInfo info)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (readerMap.TryGetValue(info, out ReadersAndUpdates rld) && rld != null)
                     {
@@ -488,11 +505,16 @@ namespace Lucene.Net.Index
                         rld.DropReaders();
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             public virtual bool AnyPendingDeletes()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     foreach (ReadersAndUpdates rld in readerMap.Values)
                     {
@@ -504,19 +526,29 @@ namespace Lucene.Net.Index
 
                     return false;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             public virtual void Release(ReadersAndUpdates rld)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     Release(rld, true);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             public virtual void Release(ReadersAndUpdates rld, bool assertInfoLive)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // Matches incRef in get:
                     rld.DecRef();
@@ -549,6 +581,10 @@ namespace Lucene.Net.Index
                         readerMap.Remove(rld.Info);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             public void Dispose()
@@ -562,7 +598,8 @@ namespace Lucene.Net.Index
             /// </summary>
             internal virtual void DropAll(bool doSave)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     Exception priorE = null;
                     foreach (var pair in readerMap)
@@ -628,6 +665,10 @@ namespace Lucene.Net.Index
                     if (Debugging.AssertsEnabled) Debugging.Assert(readerMap.Count == 0);
                     IOUtils.ReThrow(priorE);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             /// <summary>
@@ -637,7 +678,8 @@ namespace Lucene.Net.Index
             /// <exception cref="IOException"> If there is a low-level I/O error </exception>
             public virtual void Commit(SegmentInfos infos)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     foreach (SegmentCommitInfo info in infos.Segments)
                     {
@@ -660,6 +702,10 @@ namespace Lucene.Net.Index
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             /// <summary>
@@ -669,7 +715,8 @@ namespace Lucene.Net.Index
             /// </summary>
             public virtual ReadersAndUpdates Get(SegmentCommitInfo info, bool create)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (Debugging.AssertsEnabled) Debugging.Assert(info.Info.Dir == outerInstance.directory, "info.dir={0} vs {1}", info.Info.Dir, outerInstance.directory);
 
@@ -699,6 +746,10 @@ namespace Lucene.Net.Index
 
                     return rld;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             /// <summary>
@@ -896,10 +947,15 @@ namespace Lucene.Net.Index
 
                 // Default deleter (for backwards compatibility) is
                 // KeepOnlyLastCommitDeleter:
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     deleter = new IndexFileDeleter(directory, config.IndexDeletionPolicy, segmentInfos, infoStream, this, initialIndexExists);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 if (deleter.startingCommitDeleted)
                 {
@@ -1060,7 +1116,8 @@ namespace Lucene.Net.Index
         {
             // Ensure that only one thread actually gets to do the
             // closing, and make sure no commit is also in progress:
-            lock (commitLock)
+            UninterruptableMonitor.Enter(commitLock);
+            try
             {
                 if (ShouldClose())
                 {
@@ -1078,6 +1135,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(commitLock);
+            }
         }
 
         private bool AssertEventQueueAfterClose()
@@ -1100,7 +1161,8 @@ namespace Lucene.Net.Index
         /// </summary>
         private bool ShouldClose()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 while (true)
                 {
@@ -1125,6 +1187,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void CloseInternal(bool waitForMerges, bool doFlush)
@@ -1189,7 +1255,8 @@ namespace Lucene.Net.Index
                             }
                         }
 
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             for (; ; )
                             {
@@ -1212,6 +1279,10 @@ namespace Lucene.Net.Index
                             }
                             stopMerges = true;
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                     finally
                     {
@@ -1230,7 +1301,8 @@ namespace Lucene.Net.Index
                     CommitInternal();
                 }
                 ProcessEvents(false, true);
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // commitInternal calls ReaderPool.commit, which
                     // writes any pending liveDocs from ReaderPool, so
@@ -1238,6 +1310,10 @@ namespace Lucene.Net.Index
                     readerPool.DropAll(true);
                     deleter.Dispose();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 if (infoStream.IsEnabled("IW"))
                 {
@@ -1249,10 +1325,15 @@ namespace Lucene.Net.Index
                     writeLock.Dispose(); // release write lock
                     writeLock = null;
                 }
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     closed = true;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
                 if (Debugging.AssertsEnabled)
                 {
                     // LUCENENET specific - store the number of states so we don't have to call this method twice
@@ -1266,10 +1347,11 @@ namespace Lucene.Net.Index
             }
             finally
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     closing = false;
-                    Monitor.PulseAll(this);
+                    UninterruptableMonitor.PulseAll(this);
                     if (!closed)
                     {
                         if (infoStream.IsEnabled("IW"))
@@ -1278,6 +1360,10 @@ namespace Lucene.Net.Index
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
                 // finally, restore interrupt status:
                 if (interrupted)
                 {
@@ -1311,11 +1397,16 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     EnsureOpen();
                     return docWriter.NumDocs + segmentInfos.TotalDocCount;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -1331,7 +1422,8 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     EnsureOpen();
                     int count = docWriter.NumDocs;
@@ -1341,6 +1433,10 @@ namespace Lucene.Net.Index
                     }
                     return count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -1353,7 +1449,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual bool HasDeletions()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 if (bufferedUpdatesStream.Any())
@@ -1377,6 +1474,10 @@ namespace Lucene.Net.Index
                 }
                 return false;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -1607,7 +1708,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual bool TryDeleteDocument(IndexReader readerIn, int docID)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!(readerIn is AtomicReader reader))
                 {
@@ -1641,7 +1743,8 @@ namespace Lucene.Net.Index
                     ReadersAndUpdates rld = readerPool.Get(info, false);
                     if (rld != null)
                     {
-                        lock (bufferedUpdatesStream)
+                        UninterruptableMonitor.Enter(bufferedUpdatesStream);
+                        try
                         {
                             rld.InitWritableLiveDocs();
                             if (rld.Delete(docID))
@@ -1668,6 +1771,10 @@ namespace Lucene.Net.Index
                             //System.out.println("  yes " + info.info.name + " " + docID);
                             return true;
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(bufferedUpdatesStream);
+                        }
                     }
                     else
                     {
@@ -1680,6 +1787,10 @@ namespace Lucene.Net.Index
                 }
                 return false;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -1928,10 +2039,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return segmentInfos.Count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -1940,10 +2056,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return docWriter.NumDocs;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -1952,17 +2073,23 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return segmentInfos.GetFiles(directory, true);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         // for test purpose
         internal int GetDocCount(int i)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (i >= 0 && i < segmentInfos.Count)
                 {
@@ -1973,6 +2100,10 @@ namespace Lucene.Net.Index
                     return -1;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // for test purpose
@@ -1985,7 +2116,8 @@ namespace Lucene.Net.Index
         {
             // Cannot synchronize on IndexWriter because that causes
             // deadlock
-            lock (segmentInfos)
+            UninterruptableMonitor.Enter(segmentInfos);
+            try
             {
                 // Important to increment changeCount so that the
                 // segmentInfos is written on close.  Otherwise we
@@ -1996,6 +2128,10 @@ namespace Lucene.Net.Index
                 segmentInfos.Changed();
                 return "_" + (segmentInfos.Counter++).ToString(J2N.Character.MaxRadix);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(segmentInfos);
+            }
         }
 
         /// <summary>
@@ -2099,7 +2235,8 @@ namespace Lucene.Net.Index
 
             Flush(true, true);
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 ResetMergeExceptions();
                 segmentsToMerge.Clear();
@@ -2123,12 +2260,17 @@ namespace Lucene.Net.Index
                     if (merge.Info != null) segmentsToMerge[merge.Info] = true;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             MaybeMerge(MergeTrigger.EXPLICIT, maxNumSegments);
 
             if (doWait)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     while (true)
                     {
@@ -2170,6 +2312,10 @@ namespace Lucene.Net.Index
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 // If close is called while we are still
                 // running, throw an exception so the calling
@@ -2177,6 +2323,7 @@ namespace Lucene.Net.Index
                 // complete
                 EnsureOpen();
             }
+
             // NOTE: in the ConcurrentMergeScheduler case, when
             // doWait is false, we can return immediately while
             // background threads accomplish the merging
@@ -2188,7 +2335,8 @@ namespace Lucene.Net.Index
         /// </summary>
         private bool MaxNumSegmentsMergesPending()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 foreach (MergePolicy.OneMerge merge in pendingMerges)
                 {
@@ -2208,6 +2356,10 @@ namespace Lucene.Net.Index
 
                 return false;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2239,7 +2391,9 @@ namespace Lucene.Net.Index
 
             MergePolicy.MergeSpecification spec;
             bool newMergesFound = false;
-            lock (this)
+
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 spec = mergePolicy.FindForcedDeletesMerges(segmentInfos);
                 newMergesFound = spec != null;
@@ -2252,13 +2406,18 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             mergeScheduler.Merge(this, MergeTrigger.EXPLICIT, newMergesFound);
 
             if (spec != null && doWait)
             {
                 int numMerges = spec.Merges.Count;
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     bool running = true;
                     while (running)
@@ -2293,6 +2452,10 @@ namespace Lucene.Net.Index
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             // NOTE: in the ConcurrentMergeScheduler case, when
@@ -2359,7 +2522,8 @@ namespace Lucene.Net.Index
 
         private bool UpdatePendingMerges(MergeTrigger trigger, int maxNumSegments)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(maxNumSegments == -1 || maxNumSegments > 0);
                 //if (Debugging.AssertsEnabled) Debugging.Assert(trigger != null); // LUCENENET NOTE: Enum cannot be null in .NET
@@ -2377,7 +2541,7 @@ namespace Lucene.Net.Index
                 MergePolicy.MergeSpecification spec;
                 if (maxNumSegments != UNBOUNDED_MAX_MERGE_SEGMENTS)
                 {
-                    if (Debugging.AssertsEnabled) Debugging.Assert(trigger == MergeTrigger.EXPLICIT || trigger == MergeTrigger.MERGE_FINISHED,"Expected EXPLICT or MERGE_FINISHED as trigger even with maxNumSegments set but was: {0}", trigger);
+                    if (Debugging.AssertsEnabled) Debugging.Assert(trigger == MergeTrigger.EXPLICIT || trigger == MergeTrigger.MERGE_FINISHED, "Expected EXPLICT or MERGE_FINISHED as trigger even with maxNumSegments set but was: {0}", trigger);
                     spec = mergePolicy.FindForcedMerges(segmentInfos, maxNumSegments, segmentsToMerge);
                     newMergesFound = spec != null;
                     if (newMergesFound)
@@ -2405,6 +2569,10 @@ namespace Lucene.Net.Index
                 }
                 return newMergesFound;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2421,10 +2589,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return mergingSegments;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -2436,7 +2609,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual MergePolicy.OneMerge NextMerge()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (pendingMerges.Count == 0)
                 {
@@ -2450,6 +2624,10 @@ namespace Lucene.Net.Index
                     return merge;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2459,10 +2637,15 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual bool HasPendingMerges()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return pendingMerges.Count != 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2482,13 +2665,18 @@ namespace Lucene.Net.Index
 
             // Ensure that only one thread actually gets to do the
             // closing, and make sure no commit is also in progress:
-            lock (commitLock)
+            UninterruptableMonitor.Enter(commitLock);
+            try
             {
                 if (ShouldClose())
                 {
                     RollbackInternal();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(commitLock);
+            }
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)]
@@ -2503,11 +2691,16 @@ namespace Lucene.Net.Index
 
             try
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     FinishMerges(false);
                     stopMerges = true;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 if (infoStream.IsEnabled("IW"))
                 {
@@ -2523,14 +2716,15 @@ namespace Lucene.Net.Index
                 bufferedUpdatesStream.Clear();
                 docWriter.Dispose(); // mark it as closed first to prevent subsequent indexing actions/flushes
                 docWriter.Abort(this); // don't sync on IW here
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (pendingCommit != null)
                     {
                         pendingCommit.RollbackCommit(directory);
                         deleter.DecRef(pendingCommit);
                         pendingCommit = null;
-                        Monitor.PulseAll(this);
+                        UninterruptableMonitor.PulseAll(this);
                     }
 
                     // Don't bother saving any changes in our segmentInfos
@@ -2569,6 +2763,10 @@ namespace Lucene.Net.Index
                         Debugging.Assert(numDeactivatedThreadStates == docWriter.perThreadPool.MaxThreadStates, "{0} {1}", numDeactivatedThreadStates, docWriter.perThreadPool.MaxThreadStates);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 success = true;
             }
@@ -2585,7 +2783,8 @@ namespace Lucene.Net.Index
                     // e.g. TestIW.testThreadInterruptDeadlock
                     IOUtils.DisposeWhileHandlingException(mergePolicy, mergeScheduler);
                 }
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (!success)
                     {
@@ -2611,6 +2810,10 @@ namespace Lucene.Net.Index
                     closed = true;
                     closing = false;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -2644,7 +2847,8 @@ namespace Lucene.Net.Index
             /* hold the full flush lock to prevent concurrency commits / NRT reopens to
              * get in our way and do unnecessary work. -- if we don't lock this here we might
              * get in trouble if */
-            lock (fullFlushLock)
+            UninterruptableMonitor.Enter(fullFlushLock);
+            try
             {
                 /*
                  * We first abort and trash everything we have in-memory
@@ -2659,7 +2863,8 @@ namespace Lucene.Net.Index
                 {
                     docWriter.LockAndAbortAll(this);
                     ProcessEvents(false, true);
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         try
                         {
@@ -2698,17 +2903,26 @@ namespace Lucene.Net.Index
                             }
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
                 finally
                 {
                     docWriter.UnlockAllAfterAbortAll(this);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(fullFlushLock);
+            }
         }
 
         private void FinishMerges(bool waitForMerges)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!waitForMerges)
                 {
@@ -2750,7 +2964,7 @@ namespace Lucene.Net.Index
                     }
 
                     stopMerges = false;
-                    Monitor.PulseAll(this);
+                    UninterruptableMonitor.PulseAll(this);
 
                     if (Debugging.AssertsEnabled) Debugging.Assert(0 == mergingSegments.Count);
 
@@ -2769,6 +2983,10 @@ namespace Lucene.Net.Index
                     WaitForMerges();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2779,7 +2997,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual void WaitForMerges()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen(false);
                 if (infoStream.IsEnabled("IW"))
@@ -2799,6 +3018,10 @@ namespace Lucene.Net.Index
                     infoStream.Message("IW", "waitForMerges done");
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2808,11 +3031,16 @@ namespace Lucene.Net.Index
         /// </summary>
         internal virtual void Checkpoint()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Changed();
                 deleter.Checkpoint(segmentInfos, false);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -2823,33 +3051,53 @@ namespace Lucene.Net.Index
         /// </summary>
         internal virtual void CheckpointNoSIS()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 changeCount++;
                 deleter.Checkpoint(segmentInfos, false);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
         /// Called internally if any index state has changed. </summary>
         internal void Changed()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 changeCount++;
                 segmentInfos.Changed();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual void PublishFrozenUpdates(FrozenBufferedUpdates packet)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(packet != null && packet.Any());
-                lock (bufferedUpdatesStream)
+                UninterruptableMonitor.Enter(bufferedUpdatesStream);
+                try
                 {
                     bufferedUpdatesStream.Push(packet);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(bufferedUpdatesStream);
+                }
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
             }
         }
 
@@ -2861,10 +3109,12 @@ namespace Lucene.Net.Index
         {
             try
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // Lock order IW -> BDS
-                    lock (bufferedUpdatesStream)
+                    UninterruptableMonitor.Enter(bufferedUpdatesStream);
+                    try
                     {
                         if (infoStream.IsEnabled("IW"))
                         {
@@ -2896,6 +3146,14 @@ namespace Lucene.Net.Index
                         segmentInfos.Add(newSegment);
                         Checkpoint();
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(bufferedUpdatesStream);
+                    }
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
                 }
             }
             finally
@@ -2907,11 +3165,16 @@ namespace Lucene.Net.Index
 
         private void ResetMergeExceptions()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 mergeExceptions = new List<MergePolicy.OneMerge>();
                 mergeGen++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void NoDupDirs(params Directory[] dirs)
@@ -3081,7 +3344,8 @@ namespace Lucene.Net.Index
                     }
                 }
 
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     success = false;
                     try
@@ -3111,6 +3375,10 @@ namespace Lucene.Net.Index
                     segmentInfos.AddAll(infos);
                     Checkpoint();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 successTop = true;
             }
@@ -3219,10 +3487,15 @@ namespace Lucene.Net.Index
                 {
                     if (!success)
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             deleter.Refresh(info.Name);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
 
@@ -3234,7 +3507,8 @@ namespace Lucene.Net.Index
                 SetDiagnostics(info, SOURCE_ADDINDEXES_READERS);
 
                 bool useCompoundFile;
-                lock (this) // Guard segmentInfos
+                UninterruptableMonitor.Enter(this); // Guard segmentInfos
+                try
                 {
                     if (stopMerges)
                     {
@@ -3244,6 +3518,10 @@ namespace Lucene.Net.Index
                     EnsureOpen();
                     useCompoundFile = mergePolicy.UseCompoundFile(segmentInfos, infoPerCommit);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 // Now create the compound file if needed
                 if (useCompoundFile)
@@ -3257,10 +3535,15 @@ namespace Lucene.Net.Index
                     {
                         // delete new non cfs files directly: they were never
                         // registered with IFD
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             deleter.DeleteNewFiles(filesToDelete);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                     info.UseCompoundFile = true;
                 }
@@ -3279,17 +3562,23 @@ namespace Lucene.Net.Index
                 {
                     if (!success)
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             deleter.Refresh(info.Name);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
 
                 info.AddFiles(trackingDir.CreatedFiles);
 
                 // Register the new segment
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (stopMerges)
                     {
@@ -3300,6 +3589,10 @@ namespace Lucene.Net.Index
                     segmentInfos.Add(infoPerCommit);
                     Checkpoint();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
             catch (Exception oom) when (oom.IsOutOfMemoryError())
             {
@@ -3502,7 +3795,8 @@ namespace Lucene.Net.Index
 
         private void PrepareCommitInternal()
         {
-            lock (commitLock)
+            UninterruptableMonitor.Enter(commitLock);
+            try
             {
                 EnsureOpen(false);
                 if (infoStream.IsEnabled("IW"))
@@ -3533,7 +3827,8 @@ namespace Lucene.Net.Index
 
                 try
                 {
-                    lock (fullFlushLock)
+                    UninterruptableMonitor.Enter(fullFlushLock);
+                    try
                     {
                         bool flushSuccess = false;
                         bool success = false;
@@ -3549,7 +3844,8 @@ namespace Lucene.Net.Index
                             ProcessEvents(false, true);
                             flushSuccess = true;
 
-                            lock (this)
+                            UninterruptableMonitor.Enter(this);
+                            try
                             {
                                 MaybeApplyDeletes(true);
 
@@ -3572,6 +3868,10 @@ namespace Lucene.Net.Index
                                 filesToCommit = toCommit.GetFiles(directory, false);
                                 deleter.IncRef(filesToCommit);
                             }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(this);
+                            }
                             success = true;
                         }
                         finally
@@ -3588,6 +3888,10 @@ namespace Lucene.Net.Index
                             DoAfterFlush();
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(fullFlushLock);
+                    }
                 }
                 catch (Exception oom) when (oom.IsOutOfMemoryError())
                 {
@@ -3608,7 +3912,8 @@ namespace Lucene.Net.Index
                 {
                     if (!success_)
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             if (filesToCommit != null)
                             {
@@ -3616,9 +3921,17 @@ namespace Lucene.Net.Index
                                 filesToCommit = null;
                             }
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(commitLock);
+            }
         }
 
         /// <summary>
@@ -3633,11 +3946,16 @@ namespace Lucene.Net.Index
         /// </summary>
         public void SetCommitData(IDictionary<string, string> commitUserData)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 segmentInfos.UserData = new Dictionary<string, string>(commitUserData);
                 ++changeCount;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -3648,10 +3966,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return segmentInfos.UserData;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -3717,7 +4040,8 @@ namespace Lucene.Net.Index
                 infoStream.Message("IW", "commit: start");
             }
 
-            lock (commitLock)
+            UninterruptableMonitor.Enter(commitLock);
+            try
             {
                 EnsureOpen(false);
 
@@ -3744,11 +4068,16 @@ namespace Lucene.Net.Index
 
                 FinishCommit();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(commitLock);
+            }
         }
 
         private void FinishCommit()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (pendingCommit != null)
                 {
@@ -3776,7 +4105,7 @@ namespace Lucene.Net.Index
                         deleter.DecRef(filesToCommit);
                         filesToCommit = null;
                         pendingCommit = null;
-                        Monitor.PulseAll(this);
+                        UninterruptableMonitor.PulseAll(this);
                     }
                 }
                 else
@@ -3792,6 +4121,10 @@ namespace Lucene.Net.Index
                     infoStream.Message("IW", "commit: done");
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -3801,7 +4134,7 @@ namespace Lucene.Net.Index
         private readonly object fullFlushLock = new object();
 
         // for assert
-        internal virtual bool HoldsFullFlushLock => Monitor.IsEntered(fullFlushLock);
+        internal virtual bool HoldsFullFlushLock => UninterruptableMonitor.IsEntered(fullFlushLock);
 
         /// <summary>
         /// Flush all in-memory buffered updates (adds and deletes)
@@ -3847,7 +4180,8 @@ namespace Lucene.Net.Index
                 }
                 bool anySegmentFlushed;
 
-                lock (fullFlushLock)
+                UninterruptableMonitor.Enter(fullFlushLock);
+                try
                 {
                     bool flushSuccess = false;
                     try
@@ -3861,7 +4195,12 @@ namespace Lucene.Net.Index
                         ProcessEvents(false, true);
                     }
                 }
-                lock (this)
+                finally
+                {
+                    UninterruptableMonitor.Exit(fullFlushLock);
+                }
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     MaybeApplyDeletes(applyAllDeletes);
                     DoAfterFlush();
@@ -3873,6 +4212,10 @@ namespace Lucene.Net.Index
                     success = true;
                     return anySegmentFlushed;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
             catch (Exception oom) when (oom.IsOutOfMemoryError())
             {
@@ -3894,7 +4237,8 @@ namespace Lucene.Net.Index
 
         internal void MaybeApplyDeletes(bool applyAllDeletes)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (applyAllDeletes)
                 {
@@ -3909,11 +4253,16 @@ namespace Lucene.Net.Index
                     infoStream.Message("IW", "don't apply deletes now delTermCount=" + bufferedUpdatesStream.NumTerms + " bytesUsed=" + bufferedUpdatesStream.BytesUsed);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal void ApplyAllDeletesAndUpdates()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 flushDeletesCount.IncrementAndGet();
                 BufferedUpdatesStream.ApplyDeletesResult result;
@@ -3944,6 +4293,10 @@ namespace Lucene.Net.Index
                 }
                 bufferedUpdatesStream.Prune(segmentInfos);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -3966,16 +4319,22 @@ namespace Lucene.Net.Index
         /// </summary>
         public int NumRamDocs()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 return docWriter.NumDocs;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void EnsureValidMerge(MergePolicy.OneMerge merge)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 foreach (SegmentCommitInfo info in merge.Segments)
                 {
@@ -3985,6 +4344,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private static void SkipDeletedDoc(DocValuesFieldUpdates.Iterator[] updatesIters, int deletedDoc) // LUCENENET: CA1822: Mark members as static
@@ -4067,7 +4430,8 @@ namespace Lucene.Net.Index
         /// </summary>
         private ReadersAndUpdates CommitMergedDeletesAndUpdates(MergePolicy.OneMerge merge, MergeState mergeState)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(TestPoint("startCommitMergeDeletes"));
 
@@ -4095,7 +4459,7 @@ namespace Lucene.Net.Index
                     IBits prevLiveDocs = merge.readers[i].LiveDocs;
                     ReadersAndUpdates rld = readerPool.Get(info, false);
                     // We hold a ref so it should still be in the pool:
-                    if (Debugging.AssertsEnabled) Debugging.Assert(rld != null,"seg={0}", info.Info.Name);
+                    if (Debugging.AssertsEnabled) Debugging.Assert(rld != null, "seg={0}", info.Info.Name);
                     IBits currentLiveDocs = rld.LiveDocs;
                     IDictionary<string, DocValuesFieldUpdates> mergingFieldUpdates = rld.MergingFieldUpdates;
                     string[] mergingFields;
@@ -4302,11 +4666,16 @@ namespace Lucene.Net.Index
 
                 return holder.mergedDeletesAndUpdates;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool CommitMerge(MergePolicy.OneMerge merge, MergeState mergeState)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(TestPoint("startCommitMerge"));
 
@@ -4463,6 +4832,10 @@ namespace Lucene.Net.Index
 
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void HandleMergeException(Exception t, MergePolicy.OneMerge merge)
@@ -4537,7 +4910,8 @@ namespace Lucene.Net.Index
                 }
                 finally
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         MergeFinish(merge);
 
@@ -4561,6 +4935,10 @@ namespace Lucene.Net.Index
                             UpdatePendingMerges(MergeTrigger.MERGE_FINISHED, merge.MaxNumSegments);
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
             catch (Exception oom) when (oom.IsOutOfMemoryError())
@@ -4592,7 +4970,8 @@ namespace Lucene.Net.Index
         /// </summary>
         internal bool RegisterMerge(MergePolicy.OneMerge merge)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (merge.registerDone)
                 {
@@ -4697,6 +5076,10 @@ namespace Lucene.Net.Index
 
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -4705,7 +5088,8 @@ namespace Lucene.Net.Index
         /// </summary>
         internal void MergeInit(MergePolicy.OneMerge merge)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 bool success = false;
                 try
@@ -4725,11 +5109,16 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void MergeInitImpl(MergePolicy.OneMerge merge) // LUCENENET specific: renamed from _mergeInit
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled)
                 {
@@ -4810,6 +5199,10 @@ namespace Lucene.Net.Index
                     infoStream.Message("IW", "merge seg=" + merge.info.Info.Name + " " + SegString(merge.Segments));
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal static void SetDiagnostics(SegmentInfo info, string source)
@@ -4843,11 +5236,12 @@ namespace Lucene.Net.Index
         /// </summary>
         public void MergeFinish(MergePolicy.OneMerge merge)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // forceMerge, addIndexes or finishMerges may be waiting
                 // on merges to finish.
-                Monitor.PulseAll(this);
+                UninterruptableMonitor.PulseAll(this);
 
                 // It's possible we are called twice, eg if there was an
                 // exception inside mergeInit
@@ -4863,11 +5257,16 @@ namespace Lucene.Net.Index
 
                 runningMerges.Remove(merge);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void CloseMergeReaders(MergePolicy.OneMerge merge, bool suppressExceptions)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 int numSegments = merge.readers.Count;
                 Exception th = null;
@@ -4916,6 +5315,10 @@ namespace Lucene.Net.Index
                     IOUtils.ReThrow(th);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -4962,7 +5365,8 @@ namespace Lucene.Net.Index
                     IBits liveDocs;
                     int delCount;
 
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         // Must sync to ensure BufferedDeletesStream cannot change liveDocs,
                         // pendingDeleteCount and field updates while we pull a copy:
@@ -4992,6 +5396,10 @@ namespace Lucene.Net.Index
                             }
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
 
                     // Deletes might have happened after we pulled the merge reader and
                     // before we got a read-only copy of the segment's actual live docs
@@ -5053,10 +5461,15 @@ namespace Lucene.Net.Index
                 {
                     if (!success3)
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             deleter.Refresh(merge.info.Info.Name);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
                 if (Debugging.AssertsEnabled) Debugging.Assert(mergeState.SegmentInfo == merge.info.Info);
@@ -5081,10 +5494,15 @@ namespace Lucene.Net.Index
                 // this segment:
                 //System.out.println("merger set hasProx=" + merger.hasProx() + " seg=" + merge.info.name);
                 bool useCompoundFile;
-                lock (this) // Guard segmentInfos
+                UninterruptableMonitor.Enter(this); // Guard segmentInfos
+                try
                 {
                     useCompoundFile = mergePolicy.UseCompoundFile(segmentInfos, merge.info);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 if (useCompoundFile)
                 {
@@ -5099,7 +5517,8 @@ namespace Lucene.Net.Index
                     }
                     catch (Exception ioe) when (ioe.IsIOException())
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             if (merge.IsAborted)
                             {
@@ -5112,6 +5531,10 @@ namespace Lucene.Net.Index
                                 HandleMergeException(ioe, merge);
                             }
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                     catch (Exception t) when (t.IsThrowable())
                     {
@@ -5126,12 +5549,17 @@ namespace Lucene.Net.Index
                                 infoStream.Message("IW", "hit exception creating compound file during merge");
                             }
 
-                            lock (this)
+                            UninterruptableMonitor.Enter(this);
+                            try
                             {
                                 deleter.DeleteFile(Lucene.Net.Index.IndexFileNames.SegmentFileName(mergedName, "", Lucene.Net.Index.IndexFileNames.COMPOUND_FILE_EXTENSION));
                                 deleter.DeleteFile(Lucene.Net.Index.IndexFileNames.SegmentFileName(mergedName, "", Lucene.Net.Index.IndexFileNames.COMPOUND_FILE_ENTRIES_EXTENSION));
                                 deleter.DeleteNewFiles(merge.info.GetFiles());
                             }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(this);
+                            }
                         }
                     }
 
@@ -5140,7 +5568,8 @@ namespace Lucene.Net.Index
                     // per-segment readers in the finally clause below:
                     success = false;
 
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         // delete new non cfs files directly: they were never
                         // registered with IFD
@@ -5157,6 +5586,10 @@ namespace Lucene.Net.Index
                             return 0;
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
 
                     merge.info.Info.UseCompoundFile = true;
                 }
@@ -5182,10 +5615,15 @@ namespace Lucene.Net.Index
                 {
                     if (!success2)
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             deleter.DeleteNewFiles(merge.info.GetFiles());
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
 
@@ -5209,11 +5647,16 @@ namespace Lucene.Net.Index
                     }
                     finally
                     {
-                        lock (this)
+                        UninterruptableMonitor.Enter(this);
+                        try
                         {
                             rld.Release(sr);
                             readerPool.Release(rld);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(this);
+                        }
                     }
                 }
 
@@ -5243,7 +5686,8 @@ namespace Lucene.Net.Index
 
         internal virtual void AddMergeException(MergePolicy.OneMerge merge)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(merge.Exception != null);
                 if (!mergeExceptions.Contains(merge) && mergeGen == merge.mergeGen)
@@ -5251,6 +5695,10 @@ namespace Lucene.Net.Index
                     mergeExceptions.Add(merge);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // For test purposes.
@@ -5262,10 +5710,15 @@ namespace Lucene.Net.Index
         // utility routines for tests
         internal virtual SegmentCommitInfo NewestSegment()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return segmentInfos.Count > 0 ? segmentInfos.Info(segmentInfos.Count - 1) : null;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -5276,10 +5729,15 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual string SegString()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return SegString(segmentInfos.Segments);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -5290,7 +5748,8 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual string SegString(IEnumerable<SegmentCommitInfo> infos)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 StringBuilder buffer = new StringBuilder();
                 foreach (SegmentCommitInfo info in infos)
@@ -5303,6 +5762,10 @@ namespace Lucene.Net.Index
                 }
                 return buffer.ToString();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -5313,15 +5776,21 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual string SegString(SegmentCommitInfo info)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return info.ToString(info.Info.Dir, NumDeletedDocs(info) - info.DelCount);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void DoWait()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // NOTE: the callers of this method should in theory
                 // be able to do simply wait(), but, as a defense
@@ -5331,13 +5800,17 @@ namespace Lucene.Net.Index
                 // conditions are satisfied:
                 try
                 {
-                    Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+                    UninterruptableMonitor.Wait(this, TimeSpan.FromMilliseconds(1000));
                 }
                 catch (Exception ie) when (ie.IsInterruptedException())
                 {
                     throw new Util.ThreadInterruptedException(ie);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool keepFullyDeletedSegments;
@@ -5377,7 +5850,8 @@ namespace Lucene.Net.Index
         // For infoStream output
         internal virtual SegmentInfos ToLiveInfos(SegmentInfos sis)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 SegmentInfos newSIS = new SegmentInfos();
                 IDictionary<SegmentCommitInfo, SegmentCommitInfo> liveSIS = new Dictionary<SegmentCommitInfo, SegmentCommitInfo>();
@@ -5397,6 +5871,10 @@ namespace Lucene.Net.Index
 
                 return newSIS;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -5426,7 +5904,8 @@ namespace Lucene.Net.Index
                     infoStream.Message("IW", "StartCommit(): start");
                 }
 
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (Debugging.AssertsEnabled) Debugging.Assert(lastCommitChangeCount <= changeCount,"lastCommitChangeCount={0} changeCount={1}", lastCommitChangeCount, changeCount);
 
@@ -5448,6 +5927,10 @@ namespace Lucene.Net.Index
 
                     if (Debugging.AssertsEnabled) Debugging.Assert(FilesExist(toSync));
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 if (Debugging.AssertsEnabled) Debugging.Assert(TestPoint("midStartCommit"));
 
@@ -5457,7 +5940,8 @@ namespace Lucene.Net.Index
                 {
                     if (Debugging.AssertsEnabled) Debugging.Assert(TestPoint("midStartCommit2"));
 
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         if (Debugging.AssertsEnabled) Debugging.Assert(pendingCommit == null);
 
@@ -5472,6 +5956,10 @@ namespace Lucene.Net.Index
                         pendingCommitSet = true;
                         pendingCommit = toSync;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
 
                     // this call can take a long time -- 10s of seconds
                     // or more.  We do it without syncing on this:
@@ -5502,7 +5990,8 @@ namespace Lucene.Net.Index
                 }
                 finally
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         // Have our master segmentInfos record the
                         // generations we just prepared.  We do this
@@ -5522,6 +6011,10 @@ namespace Lucene.Net.Index
                             filesToCommit = null;
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
             catch (Exception oom) when (oom.IsOutOfMemoryError())
@@ -5618,7 +6111,8 @@ namespace Lucene.Net.Index
 
         internal virtual bool NrtIsCurrent(SegmentInfos infos)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 //System.out.println("IW.nrtIsCurrent " + (infos.version == segmentInfos.version && !docWriter.anyChanges() && !bufferedDeletesStream.any()));
                 EnsureOpen();
@@ -5628,16 +6122,25 @@ namespace Lucene.Net.Index
                 }
                 return infos.Version == segmentInfos.Version && !docWriter.AnyChanges() && !bufferedUpdatesStream.Any();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual bool IsClosed
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return closed;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -5669,12 +6172,17 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual void DeleteUnusedFiles()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen(false);
                 deleter.DeletePendingFiles();
                 deleter.RevisitPolicy();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // LUCENENET specific - DeletePendingFiles() excluded because it is not referenced - IDE0051
@@ -5752,10 +6260,15 @@ namespace Lucene.Net.Index
         /// <seealso cref="IndexFileDeleter.DeleteNewFiles(ICollection{string})"/>
         internal void DeleteNewFiles(ICollection<string> files)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 deleter.DeleteNewFiles(files);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -5763,10 +6276,15 @@ namespace Lucene.Net.Index
         /// <seealso cref="IndexFileDeleter.Refresh(string)"/>
         internal void FlushFailed(SegmentInfo info)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 deleter.Refresh(info.Name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal int Purge(bool forced)
@@ -5804,20 +6322,30 @@ namespace Lucene.Net.Index
 
         internal virtual void IncRefDeleter(SegmentInfos segmentInfos)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 deleter.IncRef(segmentInfos, false);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual void DecRefDeleter(SegmentInfos segmentInfos)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 deleter.DecRef(segmentInfos);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool ProcessEvents(bool triggerMerge, bool forcePurge)
diff --git a/src/Lucene.Net/Index/MergePolicy.cs b/src/Lucene.Net/Index/MergePolicy.cs
index cf6f5ac..606e36c 100644
--- a/src/Lucene.Net/Index/MergePolicy.cs
+++ b/src/Lucene.Net/Index/MergePolicy.cs
@@ -1,5 +1,6 @@
 using J2N.Collections.Generic.Extensions;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -229,17 +230,27 @@ namespace Lucene.Net.Index
             {
                 set
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         this.error = value;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         return error;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
@@ -251,10 +262,15 @@ namespace Lucene.Net.Index
             [MethodImpl(MethodImplOptions.NoInlining)]
             internal virtual void Abort()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     aborted = true;
-                    Monitor.PulseAll(this);
+                    UninterruptableMonitor.PulseAll(this);
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
                 }
             }
 
@@ -264,10 +280,15 @@ namespace Lucene.Net.Index
             {
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         return aborted;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
@@ -277,7 +298,8 @@ namespace Lucene.Net.Index
             /// </summary>
             public virtual void CheckAborted(Directory dir)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (aborted)
                     {
@@ -290,7 +312,7 @@ namespace Lucene.Net.Index
                         {
                             //In theory we could wait() indefinitely, but we
                             // do 1000 msec, defensively
-                            Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+                            UninterruptableMonitor.Wait(this, TimeSpan.FromMilliseconds(1000));
                         }
                         catch (Exception ie) when (ie.IsInterruptedException())
                         {
@@ -303,6 +325,10 @@ namespace Lucene.Net.Index
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             /// <summary>
@@ -312,15 +338,20 @@ namespace Lucene.Net.Index
             /// </summary>
             internal virtual void SetPause(bool paused)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     this.paused = paused;
                     if (!paused)
                     {
                         // Wakeup merge thread, if it's waiting
-                        Monitor.PulseAll(this);
+                        UninterruptableMonitor.PulseAll(this);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             /// <summary>
@@ -331,10 +362,15 @@ namespace Lucene.Net.Index
             {
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         return paused;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
diff --git a/src/Lucene.Net/Index/MultiReader.cs b/src/Lucene.Net/Index/MultiReader.cs
index acbdd14..dd4d090 100644
--- a/src/Lucene.Net/Index/MultiReader.cs
+++ b/src/Lucene.Net/Index/MultiReader.cs
@@ -1,4 +1,5 @@
-using System;
+using Lucene.Net.Support.Threading;
+using System;
 using System.IO;
 using System.Runtime.ExceptionServices;
 
@@ -73,7 +74,8 @@ namespace Lucene.Net.Index
 
         protected internal override void DoClose()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Exception ioe = null; // LUCENENET: No need to cast to IOExcpetion
                 foreach (IndexReader r in GetSequentialSubReaders())
@@ -103,6 +105,10 @@ namespace Lucene.Net.Index
                     ExceptionDispatchInfo.Capture(ioe).Throw(); // LUCENENET: Rethrow to preserve stack details from the original throw
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Index/ParallelAtomicReader.cs b/src/Lucene.Net/Index/ParallelAtomicReader.cs
index d9db780..8199766 100644
--- a/src/Lucene.Net/Index/ParallelAtomicReader.cs
+++ b/src/Lucene.Net/Index/ParallelAtomicReader.cs
@@ -1,5 +1,6 @@
 using J2N.Runtime.CompilerServices;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -284,7 +285,8 @@ namespace Lucene.Net.Index
 
         protected internal override void DoClose()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Exception ioe = null; // LUCENENET: No need to cast to IOExcpetion
                 foreach (AtomicReader reader in completeReaderSet)
@@ -314,6 +316,10 @@ namespace Lucene.Net.Index
                     ExceptionDispatchInfo.Capture(ioe).Throw(); // LUCENENET: Rethrow to preserve stack details from the original throw
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override NumericDocValues GetNumericDocValues(string field)
diff --git a/src/Lucene.Net/Index/ParallelCompositeReader.cs b/src/Lucene.Net/Index/ParallelCompositeReader.cs
index 9ada68a..437c0a8 100644
--- a/src/Lucene.Net/Index/ParallelCompositeReader.cs
+++ b/src/Lucene.Net/Index/ParallelCompositeReader.cs
@@ -1,6 +1,7 @@
 using J2N.Runtime.CompilerServices;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -222,7 +223,8 @@ namespace Lucene.Net.Index
 
         protected internal override void DoClose()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Exception ioe = null; // LUCENENET: No need to cast to IOExcpetion
                 foreach (IndexReader reader in completeReaderSet)
@@ -252,6 +254,10 @@ namespace Lucene.Net.Index
                     ExceptionDispatchInfo.Capture(ioe).Throw(); // LUCENENET: Rethrow to preserve stack details from the original throw
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Index/PersistentSnapshotDeletionPolicy.cs b/src/Lucene.Net/Index/PersistentSnapshotDeletionPolicy.cs
index f9bcdb9..1688718 100644
--- a/src/Lucene.Net/Index/PersistentSnapshotDeletionPolicy.cs
+++ b/src/Lucene.Net/Index/PersistentSnapshotDeletionPolicy.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -124,7 +125,8 @@ namespace Lucene.Net.Index
         /// <seealso cref="SnapshotDeletionPolicy.Snapshot()"/>
         public override IndexCommit Snapshot()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 IndexCommit ic = base.Snapshot();
                 bool success = false;
@@ -149,6 +151,10 @@ namespace Lucene.Net.Index
                 }
                 return ic;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -158,7 +164,8 @@ namespace Lucene.Net.Index
         /// <seealso cref="SnapshotDeletionPolicy.Release(IndexCommit)"/>
         public override void Release(IndexCommit commit)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 base.Release(commit);
                 bool success = false;
@@ -182,6 +189,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -192,17 +203,23 @@ namespace Lucene.Net.Index
         /// <seealso cref="SnapshotDeletionPolicy.Release(IndexCommit)"/>
         public virtual void Release(long gen)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 base.ReleaseGen(gen);
                 Persist();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)]
         internal void Persist()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 string fileName = SNAPSHOTS_PREFIX + nextWriteGen;
                 IndexOutput @out = dir.CreateOutput(fileName, IOContext.DEFAULT);
@@ -255,11 +272,16 @@ namespace Lucene.Net.Index
 
                 nextWriteGen++;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private void ClearPriorSnapshots()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 foreach (string file in dir.ListAll())
                 {
@@ -269,6 +291,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -298,7 +324,8 @@ namespace Lucene.Net.Index
         /// </summary>
         private void LoadPriorSnapshots()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 long genLoaded = -1;
                 Exception ioe = null; // LUCENENET: No need to cast to IOExcpetion
@@ -371,6 +398,10 @@ namespace Lucene.Net.Index
                     nextWriteGen = 1 + genLoaded;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Index/ReadersAndUpdates.cs b/src/Lucene.Net/Index/ReadersAndUpdates.cs
index 6cd440a..8dcfde1 100644
--- a/src/Lucene.Net/Index/ReadersAndUpdates.cs
+++ b/src/Lucene.Net/Index/ReadersAndUpdates.cs
@@ -1,6 +1,7 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -125,17 +126,23 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return pendingDeleteCount;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         // Call only from assert!
         public virtual bool VerifyDocCounts()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 int count;
                 if (liveDocs != null)
@@ -157,6 +164,10 @@ namespace Lucene.Net.Index
                 if (Debugging.AssertsEnabled) Debugging.Assert(Info.Info.DocCount - Info.DelCount - pendingDeleteCount == count, "info.docCount={0} info.DelCount={1} pendingDeleteCount={2} count={3}", Info.Info.DocCount, Info.DelCount, pendingDeleteCount, count);
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -182,7 +193,8 @@ namespace Lucene.Net.Index
         // index):
         public virtual SegmentReader GetMergeReader(IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 //System.out.println("  livedocs=" + rld.liveDocs);
 
@@ -215,25 +227,35 @@ namespace Lucene.Net.Index
                 mergeReader.IncRef();
                 return mergeReader;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void Release(SegmentReader sr)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(Info == sr.SegmentInfo);
                 sr.DecRef();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual bool Delete(int docID)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled)
                 {
                     Debugging.Assert(liveDocs != null);
-                    Debugging.Assert(Monitor.IsEntered(writer));
+                    Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                     Debugging.Assert(docID >= 0 && docID < liveDocs.Length, "out of bounds: docid={0} liveDocsLength={1} seg={2} docCount={3}", docID, liveDocs.Length, Info.Info.Name, Info.Info.DocCount);
                     Debugging.Assert(!liveDocsShared);
                 }
@@ -246,12 +268,17 @@ namespace Lucene.Net.Index
                 }
                 return didDelete;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // NOTE: removes callers ref
         public virtual void DropReaders()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // TODO: can we somehow use IOUtils here...?  problem is
                 // we are calling .decRef not .close)...
@@ -288,6 +315,10 @@ namespace Lucene.Net.Index
 
                 DecRef();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -297,7 +328,8 @@ namespace Lucene.Net.Index
         [MethodImpl(MethodImplOptions.NoInlining)]
         public virtual SegmentReader GetReadOnlyClone(IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (reader == null)
                 {
@@ -316,15 +348,20 @@ namespace Lucene.Net.Index
                     return reader;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void InitWritableLiveDocs()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled)
                 {
-                    Debugging.Assert(Monitor.IsEntered(writer));
+                    Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                     Debugging.Assert(Info.Info.DocCount > 0);
                 }
                 //System.out.println("initWritableLivedocs seg=" + info + " liveDocs=" + liveDocs + " shared=" + shared);
@@ -347,37 +384,52 @@ namespace Lucene.Net.Index
                     liveDocsShared = false;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual IBits LiveDocs
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
-                    if (Debugging.AssertsEnabled) Debugging.Assert(Monitor.IsEntered(writer));
+                    if (Debugging.AssertsEnabled) Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                     return liveDocs;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         public virtual IBits GetReadOnlyLiveDocs()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 //System.out.println("getROLiveDocs seg=" + info);
-                if (Debugging.AssertsEnabled) Debugging.Assert(Monitor.IsEntered(writer));
+                if (Debugging.AssertsEnabled) Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                 liveDocsShared = true;
                 //if (liveDocs != null) {
                 //System.out.println("  liveCount=" + liveDocs.count());
                 //}
                 return liveDocs;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void DropChanges()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // Discard (don't save) changes when we are dropping
                 // the reader; this is used only on the sub-readers
@@ -389,6 +441,10 @@ namespace Lucene.Net.Index
                 pendingDeleteCount = 0;
                 DropMergingUpdates();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // Commit live docs (writes new _X_N.del files) and field updates (writes new
@@ -398,9 +454,10 @@ namespace Lucene.Net.Index
         [MethodImpl(MethodImplOptions.NoInlining)]
         public virtual bool WriteLiveDocs(Directory dir)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
-                if (Debugging.AssertsEnabled) Debugging.Assert(Monitor.IsEntered(writer));
+                if (Debugging.AssertsEnabled) Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                 //System.out.println("rld.writeLiveDocs seg=" + info + " pendingDelCount=" + pendingDeleteCount + " numericUpdates=" + numericUpdates);
                 if (pendingDeleteCount == 0)
                 {
@@ -457,15 +514,20 @@ namespace Lucene.Net.Index
 
                 return true;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // Writes field updates (new _X_N updates files) to the directory
         [MethodImpl(MethodImplOptions.NoInlining)]
         public virtual void WriteFieldUpdates(Directory dir, DocValuesFieldUpdates.Container dvUpdates)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
-                if (Debugging.AssertsEnabled) Debugging.Assert(Monitor.IsEntered(writer));
+                if (Debugging.AssertsEnabled) Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                 //System.out.println("rld.writeFieldUpdates: seg=" + info + " numericFieldUpdates=" + numericFieldUpdates);
 
                 if (Debugging.AssertsEnabled) Debugging.Assert(dvUpdates.Any());
@@ -674,6 +736,10 @@ namespace Lucene.Net.Index
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -751,9 +817,10 @@ namespace Lucene.Net.Index
         /// </summary>
         internal virtual SegmentReader GetReaderForMerge(IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
-                if (Debugging.AssertsEnabled) Debugging.Assert(Monitor.IsEntered(writer));
+                if (Debugging.AssertsEnabled) Debugging.Assert(UninterruptableMonitor.IsEntered(writer));
                 // must execute these two statements as atomic operation, otherwise we
                 // could lose updates if e.g. another thread calls writeFieldUpdates in
                 // between, or the updates are applied to the obtained reader, but then
@@ -762,6 +829,10 @@ namespace Lucene.Net.Index
                 isMerging = true;
                 return GetReader(context);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -770,11 +841,16 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual void DropMergingUpdates()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 mergingDVUpdates.Clear();
                 isMerging = false;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -783,10 +859,15 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return mergingDVUpdates;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Index/SegmentCoreReaders.cs b/src/Lucene.Net/Index/SegmentCoreReaders.cs
index 0a88cb7..dda954c 100644
--- a/src/Lucene.Net/Index/SegmentCoreReaders.cs
+++ b/src/Lucene.Net/Index/SegmentCoreReaders.cs
@@ -1,8 +1,10 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using JCG = J2N.Collections.Generic;
 
@@ -195,7 +197,9 @@ namespace Lucene.Net.Index
 
         private void NotifyCoreClosedListeners(Exception th)
         {
-            lock (coreClosedListeners)
+            object syncRoot = ((ICollection)coreClosedListeners).SyncRoot;
+            UninterruptableMonitor.Enter(syncRoot);
+            try
             {
                 foreach (ICoreDisposedListener listener in coreClosedListeners)
                 {
@@ -219,6 +223,10 @@ namespace Lucene.Net.Index
                 }
                 IOUtils.ReThrowUnchecked(th);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncRoot);
+            }
         }
 
         internal void AddCoreDisposedListener(ICoreDisposedListener listener)
diff --git a/src/Lucene.Net/Index/SegmentDocValues.cs b/src/Lucene.Net/Index/SegmentDocValues.cs
index 94b6b56..d150f4f 100644
--- a/src/Lucene.Net/Index/SegmentDocValues.cs
+++ b/src/Lucene.Net/Index/SegmentDocValues.cs
@@ -1,5 +1,6 @@
 using J2N.Collections.Generic.Extensions;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
@@ -68,10 +69,15 @@ namespace Lucene.Net.Index
             protected override void Release()
             {
                 m_object.Dispose();
-                lock (outerInstance)
+                UninterruptableMonitor.Enter(outerInstance);
+                try
                 {
                     outerInstance.genDVProducers.Remove(gen);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(outerInstance);
+                }
             }
         }
 
@@ -79,7 +85,8 @@ namespace Lucene.Net.Index
         /// Returns the <see cref="DocValuesProducer"/> for the given generation. </summary>
         internal DocValuesProducer GetDocValuesProducer(long? gen, SegmentCommitInfo si, IOContext context, Directory dir, DocValuesFormat dvFormat, IList<FieldInfo> infos, int termsIndexDivisor)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!genDVProducers.TryGetValue(gen, out RefCount<DocValuesProducer> dvp))
                 {
@@ -93,6 +100,10 @@ namespace Lucene.Net.Index
                 }
                 return dvp.Get();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -101,7 +112,8 @@ namespace Lucene.Net.Index
         /// </summary>
         internal void DecRef(IList<long?> dvProducersGens)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Exception t = null;
                 foreach (long? gen in dvProducersGens)
@@ -125,6 +137,10 @@ namespace Lucene.Net.Index
                     IOUtils.ReThrow(t);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Index/SerialMergeScheduler.cs b/src/Lucene.Net/Index/SerialMergeScheduler.cs
index fcfa922..87a2f7b 100644
--- a/src/Lucene.Net/Index/SerialMergeScheduler.cs
+++ b/src/Lucene.Net/Index/SerialMergeScheduler.cs
@@ -1,3 +1,4 @@
+using Lucene.Net.Support.Threading;
 using System.Runtime.CompilerServices;
 
 namespace Lucene.Net.Index
@@ -39,7 +40,8 @@ namespace Lucene.Net.Index
         [MethodImpl(MethodImplOptions.NoInlining)]
         public override void Merge(IndexWriter writer, MergeTrigger trigger, bool newMergesFound) // LUCENENET NOTE: This was internal in the original, but the base class is public so there isn't much choice here
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 while (true)
                 {
@@ -51,6 +53,10 @@ namespace Lucene.Net.Index
                     writer.Merge(merge);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void Dispose(bool disposing)
diff --git a/src/Lucene.Net/Index/SlowCompositeReaderWrapper.cs b/src/Lucene.Net/Index/SlowCompositeReaderWrapper.cs
index 887030c..59812d3 100644
--- a/src/Lucene.Net/Index/SlowCompositeReaderWrapper.cs
+++ b/src/Lucene.Net/Index/SlowCompositeReaderWrapper.cs
@@ -1,4 +1,5 @@
-using Lucene.Net.Diagnostics;
+using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
 
 namespace Lucene.Net.Index
@@ -109,7 +110,8 @@ namespace Lucene.Net.Index
         {
             EnsureOpen();
             OrdinalMap map = null;
-            lock (cachedOrdMaps)
+            UninterruptableMonitor.Enter(cachedOrdMaps);
+            try
             {
                 if (!cachedOrdMaps.TryGetValue(field, out map))
                 {
@@ -126,6 +128,10 @@ namespace Lucene.Net.Index
                     return dv;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(cachedOrdMaps);
+            }
             // cached ordinal map
             if (FieldInfos.FieldInfo(field).DocValuesType != DocValuesType.SORTED)
             {
@@ -149,7 +155,8 @@ namespace Lucene.Net.Index
         {
             EnsureOpen();
             OrdinalMap map = null;
-            lock (cachedOrdMaps)
+            UninterruptableMonitor.Enter(cachedOrdMaps);
+            try
             {
                 if (!cachedOrdMaps.TryGetValue(field, out map))
                 {
@@ -166,6 +173,10 @@ namespace Lucene.Net.Index
                     return dv;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(cachedOrdMaps);
+            }
             // cached ordinal map
             if (FieldInfos.FieldInfo(field).DocValuesType != DocValuesType.SORTED_SET)
             {
diff --git a/src/Lucene.Net/Index/SnapshotDeletionPolicy.cs b/src/Lucene.Net/Index/SnapshotDeletionPolicy.cs
index 44c92e9..1ead843 100644
--- a/src/Lucene.Net/Index/SnapshotDeletionPolicy.cs
+++ b/src/Lucene.Net/Index/SnapshotDeletionPolicy.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 
@@ -75,16 +76,22 @@ namespace Lucene.Net.Index
 
         public override void OnCommit<T>(IList<T> commits)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 primary.OnCommit(WrapCommits(commits));
                 m_lastCommit = commits[commits.Count - 1];
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void OnInit<T>(IList<T> commits)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 initCalled = true;
                 primary.OnInit(WrapCommits(commits));
@@ -100,6 +107,10 @@ namespace Lucene.Net.Index
                     m_lastCommit = commits[commits.Count - 1];
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -109,11 +120,16 @@ namespace Lucene.Net.Index
         ///          the commit previously returned by <see cref="Snapshot()"/> </param>
         public virtual void Release(IndexCommit commit)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 long gen = commit.Generation;
                 ReleaseGen(gen);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -147,7 +163,8 @@ namespace Lucene.Net.Index
         /// Increments the refCount for this <see cref="IndexCommit"/>. </summary>
         protected internal virtual void IncRef(IndexCommit ic)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 long gen = ic.Generation;
                 int refCountInt;
@@ -162,6 +179,10 @@ namespace Lucene.Net.Index
                 }
                 m_refCounts[gen] = refCountInt + 1;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -182,7 +203,8 @@ namespace Lucene.Net.Index
         /// <returns> the <see cref="IndexCommit"/> that was snapshotted. </returns>
         public virtual IndexCommit Snapshot()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!initCalled)
                 {
@@ -198,16 +220,25 @@ namespace Lucene.Net.Index
 
                 return m_lastCommit;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
         /// Returns all <see cref="IndexCommit"/>s held by at least one snapshot. </summary>
         public virtual IList<IndexCommit> GetSnapshots()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return new List<IndexCommit>(m_indexCommits.Values);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -216,7 +247,8 @@ namespace Lucene.Net.Index
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     int total = 0;
                     foreach (var refCount in m_refCounts.Values)
@@ -226,6 +258,10 @@ namespace Lucene.Net.Index
 
                     return total;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -236,15 +272,21 @@ namespace Lucene.Net.Index
         /// </summary>
         public virtual IndexCommit GetIndexCommit(long gen)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return m_indexCommits[gen];
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override object Clone()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 SnapshotDeletionPolicy other = (SnapshotDeletionPolicy)base.Clone();
                 other.primary = (IndexDeletionPolicy)this.primary.Clone();
@@ -253,6 +295,10 @@ namespace Lucene.Net.Index
                 other.m_indexCommits = new Dictionary<long?, IndexCommit>(m_indexCommits);
                 return other;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -299,7 +345,8 @@ namespace Lucene.Net.Index
 
             public override void Delete()
             {
-                lock (outerInstance)
+                UninterruptableMonitor.Enter(outerInstance);
+                try
                 {
                     // Suppress the delete request if this commit point is
                     // currently snapshotted.
@@ -308,6 +355,10 @@ namespace Lucene.Net.Index
                         m_cp.Delete();
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(outerInstance);
+                }
             }
 
             public override Directory Directory => m_cp.Directory;
diff --git a/src/Lucene.Net/Index/StoredFieldsProcessor.cs b/src/Lucene.Net/Index/StoredFieldsProcessor.cs
index 4cbb401..342562b 100644
--- a/src/Lucene.Net/Index/StoredFieldsProcessor.cs
+++ b/src/Lucene.Net/Index/StoredFieldsProcessor.cs
@@ -1,5 +1,6 @@
-using Lucene.Net.Diagnostics;
+using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Runtime.CompilerServices;
 
@@ -99,7 +100,8 @@ namespace Lucene.Net.Index
 
         private void InitFieldsWriter(IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (fieldsWriter == null)
                 {
@@ -107,6 +109,10 @@ namespace Lucene.Net.Index
                     lastDocID = 0;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)]
diff --git a/src/Lucene.Net/Index/TermsEnum.cs b/src/Lucene.Net/Index/TermsEnum.cs
index c185b93..bb760e1 100644
--- a/src/Lucene.Net/Index/TermsEnum.cs
+++ b/src/Lucene.Net/Index/TermsEnum.cs
@@ -1,4 +1,5 @@
-using Lucene.Net.Util;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
@@ -336,10 +337,15 @@ namespace Lucene.Net.Index
             {
                 get
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         return base.Attributes;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
 
diff --git a/src/Lucene.Net/Search/CachingWrapperFilter.cs b/src/Lucene.Net/Search/CachingWrapperFilter.cs
index 22600eb..1c170b5 100644
--- a/src/Lucene.Net/Search/CachingWrapperFilter.cs
+++ b/src/Lucene.Net/Search/CachingWrapperFilter.cs
@@ -1,5 +1,6 @@
-using Lucene.Net.Diagnostics;
+using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 
@@ -171,7 +172,8 @@ namespace Lucene.Net.Search
         {
             // Sync only to pull the current set of values:
             List<DocIdSet> docIdSets;
-            lock (_cache)
+            UninterruptableMonitor.Enter(_cache);
+            try
             {
 #if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
                 docIdSets = new List<DocIdSet>();
@@ -181,6 +183,10 @@ namespace Lucene.Net.Search
                 docIdSets = new List<DocIdSet>(_cache.Values);
 #endif
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(_cache);
+            }
 
             long total = 0;
             foreach (DocIdSet dis in docIdSets)
diff --git a/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs b/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
index 954c018..b1f8020 100644
--- a/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
@@ -1,5 +1,6 @@
 using J2N;
 using J2N.Threading;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Threading;
 
@@ -103,12 +104,17 @@ namespace Lucene.Net.Search
 
         private void RefreshDone()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // if we're finishing, , make it out so that all waiting search threads will return
                 searchingGen = finish ? long.MaxValue : refreshStartGen;
                 available.Set();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             reopenCond.Reset();
         }
 
@@ -192,7 +198,9 @@ namespace Lucene.Net.Search
             {
                 throw new ArgumentException("targetGen=" + targetGen + " was never returned by the ReferenceManager instance (current gen=" + curGen + ")");
             }
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
+            {
                 if (targetGen <= searchingGen)
                     return true;
                 else
@@ -201,6 +209,11 @@ namespace Lucene.Net.Search
                     reopenCond.Set();
                     available.Reset();
                 }
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             long startMS = Time.NanoTime() / 1000000;
 
@@ -239,8 +252,15 @@ namespace Lucene.Net.Search
             {
                 bool hasWaiting;
 
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
+                {
                     hasWaiting = waitingGen > searchingGen;
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
 
                 long nextReopenStartNS = lastReopenStartNS + (hasWaiting ? targetMinStaleNS : targetMaxStaleNS);
                 long sleepNS = nextReopenStartNS - Time.NanoTime();
diff --git a/src/Lucene.Net/Search/FieldCacheImpl.cs b/src/Lucene.Net/Search/FieldCacheImpl.cs
index 8a64830..15069f1 100644
--- a/src/Lucene.Net/Search/FieldCacheImpl.cs
+++ b/src/Lucene.Net/Search/FieldCacheImpl.cs
@@ -3,6 +3,7 @@ using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
 using Lucene.Net.Support;
 using Lucene.Net.Support.IO;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -96,15 +97,21 @@ namespace Lucene.Net.Search
 
         public virtual void PurgeAllCaches()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 Init();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void PurgeByCacheKey(object coreCacheKey)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // LUCENENET specific - removed unnecessary Dictionary and loop
                 caches_typeof_sbyte.PurgeByCacheKey(coreCacheKey);
@@ -118,13 +125,18 @@ namespace Lucene.Net.Search
                 caches_typeof_DocTermOrds.PurgeByCacheKey(coreCacheKey);
                 caches_typeof_DocsWithFieldCache.PurgeByCacheKey(coreCacheKey);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual FieldCache.CacheEntry[] GetCacheEntries()
         {
             // LUCENENET specific - instantiate/ToArray() outside of lock to improve performance
             IList<FieldCache.CacheEntry> result = new List<FieldCache.CacheEntry>(17);
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // LUCENENET specific - refactored to use generic CacheKey to reduce casting and removed unnecessary Dictionary/loop
                 AddCacheEntries(result, typeof(sbyte), caches_typeof_sbyte);
@@ -138,12 +150,17 @@ namespace Lucene.Net.Search
                 AddCacheEntries(result, typeof(DocTermOrds), caches_typeof_DocTermOrds);
                 AddCacheEntries(result, typeof(DocsWithFieldCache), caches_typeof_DocsWithFieldCache);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
             return result.ToArray();
         }
 
         private void AddCacheEntries<TKey, TValue>(IList<FieldCache.CacheEntry> result, Type cacheType, Cache<TKey, TValue> cache) where TKey : CacheKey
         {
-            lock (cache.readerCache)
+            UninterruptableMonitor.Enter(cache.readerCache);
+            try
             {
                 foreach (var readerCacheEntry in cache.readerCache)
                 {
@@ -160,6 +177,10 @@ namespace Lucene.Net.Search
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(cache.readerCache);
+            }
         }
 
         // per-segment fieldcaches don't purge until the shared core closes.
@@ -245,8 +266,15 @@ namespace Lucene.Net.Search
             /// Remove this reader from the cache, if present. </summary>
             public virtual void PurgeByCacheKey(object coreCacheKey)
             {
-                lock (readerCache)
+                UninterruptableMonitor.Enter(readerCache);
+                try
+                {
                     readerCache.Remove(coreCacheKey);
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(readerCache);
+                }
             }
 
             /// <summary>
@@ -257,7 +285,8 @@ namespace Lucene.Net.Search
             {
                 IDictionary<TKey, object> innerCache;
                 object readerKey = reader.CoreCacheKey;
-                lock (readerCache)
+                UninterruptableMonitor.Enter(readerCache);
+                try
                 {
 #if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
 
@@ -286,6 +315,10 @@ namespace Lucene.Net.Search
                         innerCache[key] = value;
                     // else if another thread beat us to it, leave the current value
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(readerCache);
+                }
             }
 
             public virtual TValue Get(AtomicReader reader, TKey key, bool setDocsWithField)
@@ -293,7 +326,8 @@ namespace Lucene.Net.Search
                 IDictionary<TKey, object> innerCache;
                 object value = null;
                 object readerKey = reader.CoreCacheKey;
-                lock (readerCache)
+                UninterruptableMonitor.Enter(readerCache);
+                try
                 {
 #if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
                     innerCache = readerCache.GetValue(readerKey, (readerKey) =>
@@ -327,17 +361,27 @@ namespace Lucene.Net.Search
                             innerCache[key] = value = new FieldCache.CreationPlaceholder<TValue>();
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(readerCache);
+                }
                 if (value is FieldCache.CreationPlaceholder<TValue> progress)
                 {
-                    lock (value)
+                    UninterruptableMonitor.Enter(value);
+                    try
                     {
                         if (progress.Value is null)
                         {
                             progress.Value = CreateValue(reader, key, setDocsWithField);
-                            lock (readerCache)
+                            UninterruptableMonitor.Enter(readerCache);
+                            try
                             {
                                 innerCache[key] = progress.Value;
                             }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(readerCache);
+                            }
                             // Only check if key.custom (the parser) is
                             // non-null; else, we check twice for a single
                             // call to FieldCache.getXXX
@@ -352,6 +396,10 @@ namespace Lucene.Net.Search
                         }
                         return progress.Value;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(value);
+                    }
                 }
                 return (TValue)value;
             }
diff --git a/src/Lucene.Net/Search/ReferenceManager.cs b/src/Lucene.Net/Search/ReferenceManager.cs
index 37bd91e..c6f66df 100644
--- a/src/Lucene.Net/Search/ReferenceManager.cs
+++ b/src/Lucene.Net/Search/ReferenceManager.cs
@@ -68,13 +68,18 @@ namespace Lucene.Net.Search
 
         private void SwapReference(G newReference)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 G oldReference = current;
                 current = newReference;
                 Release(oldReference);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -173,7 +178,8 @@ namespace Lucene.Net.Search
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (current != null)
                     {
@@ -183,6 +189,10 @@ namespace Lucene.Net.Search
                         SwapReference(null);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Search/SearcherLifetimeManager.cs b/src/Lucene.Net/Search/SearcherLifetimeManager.cs
index a62eb41..36348a5 100644
--- a/src/Lucene.Net/Search/SearcherLifetimeManager.cs
+++ b/src/Lucene.Net/Search/SearcherLifetimeManager.cs
@@ -1,4 +1,5 @@
 using J2N;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -127,10 +128,15 @@ namespace Lucene.Net.Search
 
             public void Dispose()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     Searcher.IndexReader.DecRef();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -264,7 +270,8 @@ namespace Lucene.Net.Search
         /// </summary>
         public virtual void Prune(IPruner pruner)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // Cannot just pass searchers.values() to ArrayList ctor
                 // (not thread-safe since the values can change while
@@ -299,6 +306,10 @@ namespace Lucene.Net.Search
                     lastRecordTimeSec = tracker.RecordTimeSec;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -330,7 +341,8 @@ namespace Lucene.Net.Search
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     _closed = true;
                     IList<SearcherTracker> toClose = new List<SearcherTracker>(_searchers.Values.Select(item => item.Value));
@@ -350,6 +362,10 @@ namespace Lucene.Net.Search
                         throw IllegalStateException.Create("another thread called record while this SearcherLifetimeManager instance was being disposed; not all searchers were disposed");
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
     }
diff --git a/src/Lucene.Net/Search/TimeLimitingCollector.cs b/src/Lucene.Net/Search/TimeLimitingCollector.cs
index 4549503..23477cd 100644
--- a/src/Lucene.Net/Search/TimeLimitingCollector.cs
+++ b/src/Lucene.Net/Search/TimeLimitingCollector.cs
@@ -1,4 +1,5 @@
 using J2N.Threading;
+using Lucene.Net.Support.Threading;
 using System;
 #if FEATURE_SERIALIZABLE_EXCEPTIONS
 using System.Runtime.Serialization;
diff --git a/src/Lucene.Net/Store/CompoundFileDirectory.cs b/src/Lucene.Net/Store/CompoundFileDirectory.cs
index 5765045..92dca31 100644
--- a/src/Lucene.Net/Store/CompoundFileDirectory.cs
+++ b/src/Lucene.Net/Store/CompoundFileDirectory.cs
@@ -2,6 +2,7 @@
 using J2N.Numerics;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -285,7 +286,8 @@ namespace Lucene.Net.Store
 
         protected override void Dispose(bool disposing)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (disposing)
                 {
@@ -306,11 +308,16 @@ namespace Lucene.Net.Store
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override IndexInput OpenInput(string name, IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 if (Debugging.AssertsEnabled) Debugging.Assert(!openForWrite);
@@ -323,6 +330,10 @@ namespace Lucene.Net.Store
                 }
                 return handle.OpenSlice(name, entry.Offset, entry.Length);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net/Store/CompoundFileWriter.cs b/src/Lucene.Net/Store/CompoundFileWriter.cs
index 583d9d2..63f01f9 100644
--- a/src/Lucene.Net/Store/CompoundFileWriter.cs
+++ b/src/Lucene.Net/Store/CompoundFileWriter.cs
@@ -1,6 +1,7 @@
 using J2N.Collections.Generic.Extensions;
 using J2N.Threading.Atomic;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -100,7 +101,8 @@ namespace Lucene.Net.Store
 
         private IndexOutput GetOutput()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (dataOut == null)
                 {
@@ -121,6 +123,10 @@ namespace Lucene.Net.Store
                 }
                 return dataOut;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net/Store/Lock.cs b/src/Lucene.Net/Store/Lock.cs
index 0f9d167..5613439 100644
--- a/src/Lucene.Net/Store/Lock.cs
+++ b/src/Lucene.Net/Store/Lock.cs
@@ -1,4 +1,5 @@
-using System;
+using Lucene.Net.Support.Threading;
+using System;
 using System.IO;
 using System.Threading;
 
diff --git a/src/Lucene.Net/Store/LockVerifyServer.cs b/src/Lucene.Net/Store/LockVerifyServer.cs
index edfa6f0..af4c47c 100644
--- a/src/Lucene.Net/Store/LockVerifyServer.cs
+++ b/src/Lucene.Net/Store/LockVerifyServer.cs
@@ -1,4 +1,5 @@
 using J2N.Threading;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using System;
 using System.Globalization;
@@ -136,7 +137,8 @@ namespace Lucene.Net.Store
                             return; // closed
                         }
 
-                        lock (localLock)
+                        UninterruptableMonitor.Enter(localLock);
+                        try
                         {
                             int currentLock = lockedID[0];
                             if (currentLock == -2)
@@ -171,6 +173,10 @@ namespace Lucene.Net.Store
                             intWriter.Write((byte)command);
                             stream.Flush();
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(localLock);
+                        }
                     }
                 }
                 catch (Exception e) when (e.IsRuntimeException() || e.IsError())
diff --git a/src/Lucene.Net/Store/NRTCachingDirectory.cs b/src/Lucene.Net/Store/NRTCachingDirectory.cs
index ba50abf..94e9c5f 100644
--- a/src/Lucene.Net/Store/NRTCachingDirectory.cs
+++ b/src/Lucene.Net/Store/NRTCachingDirectory.cs
@@ -1,4 +1,5 @@
 using J2N.Collections.Generic.Extensions;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -120,7 +121,8 @@ namespace Lucene.Net.Store
 
         public override string[] ListAll()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 ISet<string> files = new JCG.HashSet<string>();
                 foreach (string f in cache.ListAll())
@@ -152,6 +154,10 @@ namespace Lucene.Net.Store
                 }
                 return files.ToArray();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -166,15 +172,21 @@ namespace Lucene.Net.Store
         [Obsolete("this method will be removed in 5.0")]
         public override bool FileExists(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return cache.FileExists(name) || @delegate.FileExists(name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void DeleteFile(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (VERBOSE)
                 {
@@ -191,11 +203,16 @@ namespace Lucene.Net.Store
                     @delegate.DeleteFile(name);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override long FileLength(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
 #pragma warning disable 612, 618
                 if (cache.FileExists(name))
@@ -208,6 +225,10 @@ namespace Lucene.Net.Store
                     return @delegate.FileLength(name);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual string[] ListCachedFiles()
@@ -266,7 +287,8 @@ namespace Lucene.Net.Store
 
         public override IndexInput OpenInput(string name, IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (VERBOSE)
                 {
@@ -287,11 +309,16 @@ namespace Lucene.Net.Store
                     return @delegate.OpenInput(name, context);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override IndexInputSlicer CreateSlicer(string name, IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 EnsureOpen();
                 if (VERBOSE)
@@ -313,6 +340,10 @@ namespace Lucene.Net.Store
                     return @delegate.CreateSlicer(name, context);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -364,7 +395,8 @@ namespace Lucene.Net.Store
         {
             // Only let one thread uncache at a time; this only
             // happens during commit() or close():
-            lock (uncacheLock)
+            UninterruptableMonitor.Enter(uncacheLock);
+            try
             {
                 if (VERBOSE)
                 {
@@ -391,12 +423,21 @@ namespace Lucene.Net.Store
                 }
 
                 // Lock order: uncacheLock -> this
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // Must sync here because other sync methods have
                     // if (cache.fileExists(name)) { ... } else { ... }:
                     cache.DeleteFile(fileName);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(uncacheLock);
             }
         }
     }
diff --git a/src/Lucene.Net/Store/NativeFSLockFactory.cs b/src/Lucene.Net/Store/NativeFSLockFactory.cs
index 484d889..374deee 100644
--- a/src/Lucene.Net/Store/NativeFSLockFactory.cs
+++ b/src/Lucene.Net/Store/NativeFSLockFactory.cs
@@ -3,6 +3,7 @@ using Lucene.Net.Util;
 using System;
 using System.IO;
 using System.Collections.Generic;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Store
 {
@@ -197,9 +198,16 @@ namespace Lucene.Net.Store
         {
             var path = GetCanonicalPathOfLockFile(lockName);
             Lock l;
-            lock (_locks)
+            UninterruptableMonitor.Enter(_locks);
+            try
+            {
                 if (!_locks.TryGetValue(path, out l))
                     _locks.Add(path, l = NewLock(path));
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(_locks);
+            }
             return l;
         }
 
@@ -225,12 +233,19 @@ namespace Lucene.Net.Store
             var path = GetCanonicalPathOfLockFile(lockName);
             // this is the reason why we can't use ConcurrentDictionary: we need the removal and disposal of the lock to be atomic
             // otherwise it may clash with MakeLock making a lock and ClearLock disposing of it in another thread.
-            lock (_locks)
+            UninterruptableMonitor.Enter(_locks);
+            try
+            {
                 if (_locks.TryGetValue(path, out Lock l))
                 {
                     _locks.Remove(path);
                     l.Dispose();
                 }
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(_locks);
+            }
         }
     }
 
@@ -259,7 +274,8 @@ namespace Lucene.Net.Store
 
         public override bool Obtain()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 FailureReason = null;
 
@@ -317,20 +333,32 @@ namespace Lucene.Net.Store
 
                 return channel != null;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void Dispose(bool disposing)
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // whether or not we have created a file, we need to remove
                     // the lock instance from the dictionary that tracks them.
                     try
                     {
-                        lock (NativeFSLockFactory._locks)
+                        UninterruptableMonitor.Enter(NativeFSLockFactory._locks);
+                        try
+                        {
                             NativeFSLockFactory._locks.Remove(path);
+                        }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(NativeFSLockFactory._locks);
+                        }
                     }
                     finally
                     {
@@ -361,12 +389,17 @@ namespace Lucene.Net.Store
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         public override bool IsLocked()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // The test for is isLocked is not directly possible with native file locks:
 
@@ -400,6 +433,10 @@ namespace Lucene.Net.Store
                     return false;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override string ToString()
@@ -465,7 +502,8 @@ namespace Lucene.Net.Store
 
         public override bool Obtain()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 FailureReason = null;
 
@@ -497,20 +535,32 @@ namespace Lucene.Net.Store
                 }
                 return channel != null;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void Dispose(bool disposing)
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // whether or not we have created a file, we need to remove
                     // the lock instance from the dictionary that tracks them.
                     try
                     {
-                        lock (NativeFSLockFactory._locks)
+                        UninterruptableMonitor.Enter(NativeFSLockFactory._locks);
+                        try
+                        {
                             NativeFSLockFactory._locks.Remove(path);
+                        }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(NativeFSLockFactory._locks);
+                        }
                     }
                     finally
                     {
@@ -527,12 +577,17 @@ namespace Lucene.Net.Store
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         public override bool IsLocked()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // First a shortcut, if a lock reference in this instance is available
                 if (channel != null)
@@ -557,6 +612,10 @@ namespace Lucene.Net.Store
                     return false;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override string ToString()
@@ -617,7 +676,8 @@ namespace Lucene.Net.Store
 
         public override bool Obtain()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 FailureReason = null;
 
@@ -662,20 +722,32 @@ namespace Lucene.Net.Store
                 }
                 return channel != null;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected override void Dispose(bool disposing)
         {
             if (disposing)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     // whether or not we have created a file, we need to remove
                     // the lock instance from the dictionary that tracks them.
                     try
                     {
-                        lock (NativeFSLockFactory._locks)
+                        UninterruptableMonitor.Enter(NativeFSLockFactory._locks);
+                        try
+                        {
                             NativeFSLockFactory._locks.Remove(path);
+                        }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(NativeFSLockFactory._locks);
+                        }
                     }
                     finally
                     {
@@ -700,12 +772,17 @@ namespace Lucene.Net.Store
                         }
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         public override bool IsLocked()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // First a shortcut, if a lock reference in this instance is available
                 if (channel != null)
@@ -734,6 +811,10 @@ namespace Lucene.Net.Store
                     return false;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override string ToString()
diff --git a/src/Lucene.Net/Store/RAMFile.cs b/src/Lucene.Net/Store/RAMFile.cs
index 1da3b5e..80d3bb9 100644
--- a/src/Lucene.Net/Store/RAMFile.cs
+++ b/src/Lucene.Net/Store/RAMFile.cs
@@ -1,3 +1,4 @@
+using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
 
 namespace Lucene.Net.Store
@@ -50,28 +51,43 @@ namespace Lucene.Net.Store
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return length;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
             set
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     this.length = value;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         protected internal byte[] AddBuffer(int size)
         {
             byte[] buffer = NewBuffer(size);
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 m_buffers.Add(buffer);
                 m_sizeInBytes += size;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
 
             if (directory != null)
             {
@@ -82,20 +98,30 @@ namespace Lucene.Net.Store
 
         protected internal byte[] GetBuffer(int index)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return m_buffers[index];
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         protected internal int NumBuffers
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return m_buffers.Count;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
@@ -111,10 +137,15 @@ namespace Lucene.Net.Store
 
         public virtual long GetSizeInBytes()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return m_sizeInBytes;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Store/RateLimiter.cs b/src/Lucene.Net/Store/RateLimiter.cs
index 61e2339..9e97211 100644
--- a/src/Lucene.Net/Store/RateLimiter.cs
+++ b/src/Lucene.Net/Store/RateLimiter.cs
@@ -1,4 +1,5 @@
 using J2N;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Threading;
 
diff --git a/src/Lucene.Net/Store/SimpleFSDirectory.cs b/src/Lucene.Net/Store/SimpleFSDirectory.cs
index e0a6e2e..8247314 100644
--- a/src/Lucene.Net/Store/SimpleFSDirectory.cs
+++ b/src/Lucene.Net/Store/SimpleFSDirectory.cs
@@ -1,4 +1,5 @@
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.IO;
 
@@ -205,7 +206,8 @@ namespace Lucene.Net.Store
             /// <see cref="IndexInput"/> methods </summary>
             protected override void ReadInternal(byte[] b, int offset, int len)
             {
-                lock (m_file)
+                UninterruptableMonitor.Enter(m_file);
+                try
                 {
                     long position = m_off + Position; // LUCENENET specific: Renamed from getFilePointer() to match FileStream
                     m_file.Seek(position, SeekOrigin.Begin);
@@ -242,6 +244,10 @@ namespace Lucene.Net.Store
                         throw new IOException(ioe.Message + ": " + this, ioe);
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_file);
+                }
             }
 
             protected override void SeekInternal(long position)
diff --git a/src/Lucene.Net/Store/SingleInstanceLockFactory.cs b/src/Lucene.Net/Store/SingleInstanceLockFactory.cs
index e432340..f78bc0b 100644
--- a/src/Lucene.Net/Store/SingleInstanceLockFactory.cs
+++ b/src/Lucene.Net/Store/SingleInstanceLockFactory.cs
@@ -1,3 +1,4 @@
+using Lucene.Net.Support.Threading;
 using System.Collections.Generic;
 using JCG = J2N.Collections.Generic;
 
@@ -43,13 +44,18 @@ namespace Lucene.Net.Store
 
         public override void ClearLock(string lockName)
         {
-            lock (locks)
+            UninterruptableMonitor.Enter(locks);
+            try
             {
                 if (locks.Contains(lockName))
                 {
                     locks.Remove(lockName);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(locks);
+            }
         }
     }
 
@@ -66,29 +72,44 @@ namespace Lucene.Net.Store
 
         public override bool Obtain()
         {
-            lock (locks)
+            UninterruptableMonitor.Enter(locks);
+            try
             {
                 return locks.Add(lockName);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(locks);
+            }
         }
 
         protected override void Dispose(bool disposing)
         {
             if (disposing)
             {
-                lock (locks)
+                UninterruptableMonitor.Enter(locks);
+                try
                 {
                     locks.Remove(lockName);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(locks);
+                }
             }
         }
 
         public override bool IsLocked()
         {
-            lock (locks)
+            UninterruptableMonitor.Enter(locks);
+            try
             {
                 return locks.Contains(lockName);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(locks);
+            }
         }
 
         public override string ToString()
diff --git a/src/Lucene.Net/Store/VerifyingLockFactory.cs b/src/Lucene.Net/Store/VerifyingLockFactory.cs
index bf9b71b..eff9f59 100644
--- a/src/Lucene.Net/Store/VerifyingLockFactory.cs
+++ b/src/Lucene.Net/Store/VerifyingLockFactory.cs
@@ -1,3 +1,4 @@
+using Lucene.Net.Support.Threading;
 using System;
 using System.IO;
 
@@ -66,7 +67,8 @@ namespace Lucene.Net.Store
 
             public override bool Obtain()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     bool obtained = @lock.Obtain();
                     if (obtained)
@@ -75,21 +77,31 @@ namespace Lucene.Net.Store
                     }
                     return obtained;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             public override bool IsLocked()
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     return @lock.IsLocked();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
 
             protected override void Dispose(bool disposing)
             {
                 if (disposing)
                 {
-                    lock (this)
+                    UninterruptableMonitor.Enter(this);
+                    try
                     {
                         if (IsLocked())
                         {
@@ -97,6 +109,10 @@ namespace Lucene.Net.Store
                             @lock.Dispose();
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(this);
+                    }
                 }
             }
         }
@@ -114,18 +130,28 @@ namespace Lucene.Net.Store
 
         public override Lock MakeLock(string lockName)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return new CheckedLock(this, lf.MakeLock(lockName));
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void ClearLock(string lockName)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 lf.ClearLock(lockName);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Support/Codecs/DefaultCodecFactory.cs b/src/Lucene.Net/Support/Codecs/DefaultCodecFactory.cs
index c4e74a0..c1e66e7 100644
--- a/src/Lucene.Net/Support/Codecs/DefaultCodecFactory.cs
+++ b/src/Lucene.Net/Support/Codecs/DefaultCodecFactory.cs
@@ -1,4 +1,5 @@
-using Lucene.Net.Util;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
 using System.Reflection;
@@ -218,10 +219,15 @@ namespace Lucene.Net.Codecs
         private void PutCodecTypeImpl(Type codec)
         {
             string name = GetServiceName(codec);
-            lock (m_initializationLock)
+            UninterruptableMonitor.Enter(m_initializationLock);
+            try
             {
                 codecNameToTypeMap[name] = codec;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_initializationLock);
+            }
         }
 
         /// <summary>
@@ -232,11 +238,16 @@ namespace Lucene.Net.Codecs
         public virtual Codec GetCodec(string name)
         {
             EnsureInitialized(); // Safety in case a subclass doesn't call it
-            lock (m_initializationLock)
+            UninterruptableMonitor.Enter(m_initializationLock);
+            try
             {
                 Type codecType = GetCodecType(name);
                 return GetCodec(codecType);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_initializationLock);
+            }
         }
 
         /// <summary>
@@ -250,7 +261,8 @@ namespace Lucene.Net.Codecs
                 throw new ArgumentNullException(nameof(type));
             if (!codecInstanceCache.TryGetValue(type, out Codec instance))
             {
-                lock (m_initializationLock)
+                UninterruptableMonitor.Enter(m_initializationLock);
+                try
                 {
                     if (!codecInstanceCache.TryGetValue(type, out instance))
                     {
@@ -258,6 +270,10 @@ namespace Lucene.Net.Codecs
                         codecInstanceCache[type] = instance;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_initializationLock);
+                }
             }
 
             return instance;
diff --git a/src/Lucene.Net/Support/Codecs/DefaultDocValuesFormatFactory.cs b/src/Lucene.Net/Support/Codecs/DefaultDocValuesFormatFactory.cs
index e7e1b4f..b96becf 100644
--- a/src/Lucene.Net/Support/Codecs/DefaultDocValuesFormatFactory.cs
+++ b/src/Lucene.Net/Support/Codecs/DefaultDocValuesFormatFactory.cs
@@ -1,4 +1,5 @@
-using Lucene.Net.Util;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
 using System.Reflection;
@@ -214,10 +215,15 @@ namespace Lucene.Net.Codecs
         private void PutDocValuesFormatTypeImpl(Type docValuesFormat)
         {
             string name = GetServiceName(docValuesFormat);
-            lock (m_initializationLock)
+            UninterruptableMonitor.Enter(m_initializationLock);
+            try
             {
                 docValuesFormatNameToTypeMap[name] = docValuesFormat;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_initializationLock);
+            }
         }
 
         /// <summary>
@@ -228,11 +234,16 @@ namespace Lucene.Net.Codecs
         public virtual DocValuesFormat GetDocValuesFormat(string name)
         {
             EnsureInitialized(); // Safety in case a subclass doesn't call it
-            lock (m_initializationLock)
+            UninterruptableMonitor.Enter(m_initializationLock);
+            try
             {
                 Type codecType = GetDocValuesFormatType(name);
                 return GetDocValuesFormat(codecType);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_initializationLock);
+            }
         }
 
         /// <summary>
@@ -246,7 +257,8 @@ namespace Lucene.Net.Codecs
                 throw new ArgumentNullException(nameof(type));
             if (!docValuesFormatInstanceCache.TryGetValue(type, out DocValuesFormat instance))
             {
-                lock (m_initializationLock)
+                UninterruptableMonitor.Enter(m_initializationLock);
+                try
                 {
                     if (!docValuesFormatInstanceCache.TryGetValue(type, out instance))
                     {
@@ -254,6 +266,10 @@ namespace Lucene.Net.Codecs
                         docValuesFormatInstanceCache[type] = instance;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_initializationLock);
+                }
             }
 
             return instance;
diff --git a/src/Lucene.Net/Support/Codecs/DefaultPostingsFormatFactory.cs b/src/Lucene.Net/Support/Codecs/DefaultPostingsFormatFactory.cs
index 8da5aeb..40637f2 100644
--- a/src/Lucene.Net/Support/Codecs/DefaultPostingsFormatFactory.cs
+++ b/src/Lucene.Net/Support/Codecs/DefaultPostingsFormatFactory.cs
@@ -1,4 +1,5 @@
-using Lucene.Net.Util;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
 using System.Reflection;
@@ -214,10 +215,15 @@ namespace Lucene.Net.Codecs
         private void PutPostingsFormatTypeImpl(Type postingsFormat)
         {
             string name = GetServiceName(postingsFormat);
-            lock (m_initializationLock)
+            UninterruptableMonitor.Enter(m_initializationLock);
+            try
             {
                 postingsFormatNameToTypeMap[name] = postingsFormat;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_initializationLock);
+            }
         }
 
         /// <summary>
@@ -228,11 +234,16 @@ namespace Lucene.Net.Codecs
         public virtual PostingsFormat GetPostingsFormat(string name)
         {
             EnsureInitialized(); // Safety in case a subclass doesn't call it
-            lock (m_initializationLock)
+            UninterruptableMonitor.Enter(m_initializationLock);
+            try
             {
                 Type codecType = GetPostingsFormatType(name);
                 return GetPostingsFormat(codecType);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(m_initializationLock);
+            }
         }
 
         /// <summary>
@@ -246,7 +257,8 @@ namespace Lucene.Net.Codecs
                 throw new ArgumentNullException(nameof(type));
             if (!postingsFormatInstanceCache.TryGetValue(type, out PostingsFormat instance))
             {
-                lock (m_initializationLock)
+                UninterruptableMonitor.Enter(m_initializationLock);
+                try
                 {
                     if (!postingsFormatInstanceCache.TryGetValue(type, out instance))
                     {
@@ -254,6 +266,10 @@ namespace Lucene.Net.Codecs
                         postingsFormatInstanceCache[type] = instance;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(m_initializationLock);
+                }
             }
 
             return instance;
diff --git a/src/Lucene.Net/Support/ConcurrentHashSet.cs b/src/Lucene.Net/Support/ConcurrentHashSet.cs
index c728b39..57f3c52 100644
--- a/src/Lucene.Net/Support/ConcurrentHashSet.cs
+++ b/src/Lucene.Net/Support/ConcurrentHashSet.cs
@@ -24,6 +24,7 @@ SOFTWARE.
 
 */
 
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -352,7 +353,9 @@ namespace Lucene.Net.Support
 
                 GetBucketAndLockNo(hashcode, out int bucketNo, out int lockNo, tables.Buckets.Length, tables.Locks.Length);
 
-                lock (tables.Locks[lockNo])
+                object syncRoot = tables.Locks[lockNo];
+                UninterruptableMonitor.Enter(syncRoot);
+                try
                 {
                     // If the table just got resized, we may not be holding the right lock, and must retry.
                     // This should be a rare occurrence.
@@ -383,6 +386,10 @@ namespace Lucene.Net.Support
                         previous = current;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncRoot);
+                }
 
                 return false;
             }
@@ -478,7 +485,7 @@ namespace Lucene.Net.Support
                 try
                 {
                     if (acquireLock)
-                        Monitor.Enter(tables.Locks[lockNo], ref lockTaken);
+                        UninterruptableMonitor.Enter(tables.Locks[lockNo], ref lockTaken);
 
                     // If the table just got resized, we may not be holding the right lock, and must retry.
                     // This should be a rare occurrence.
@@ -519,7 +526,7 @@ namespace Lucene.Net.Support
                 finally
                 {
                     if (lockTaken)
-                        Monitor.Exit(tables.Locks[lockNo]);
+                        UninterruptableMonitor.Exit(tables.Locks[lockNo]);
                 }
 
                 //
@@ -709,7 +716,7 @@ namespace Lucene.Net.Support
                 var lockTaken = false;
                 try
                 {
-                    Monitor.Enter(locks[i], ref lockTaken);
+                    UninterruptableMonitor.Enter(locks[i], ref lockTaken);
                 }
                 finally
                 {
@@ -727,7 +734,7 @@ namespace Lucene.Net.Support
 
             for (var i = fromInclusive; i < toExclusive; i++)
             {
-                Monitor.Exit(_tables.Locks[i]);
+                UninterruptableMonitor.Exit(_tables.Locks[i]);
             }
         }
 
diff --git a/src/Lucene.Net/Support/ConcurrentSet.cs b/src/Lucene.Net/Support/ConcurrentSet.cs
index 5619801..eaba680 100644
--- a/src/Lucene.Net/Support/ConcurrentSet.cs
+++ b/src/Lucene.Net/Support/ConcurrentSet.cs
@@ -1,4 +1,5 @@
 using J2N.Text;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -42,92 +43,197 @@ namespace Lucene.Net.Support
 
         public bool Add(T item)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.Add(item);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public void ExceptWith(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.ExceptWith(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public void IntersectWith(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.IntersectWith(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool IsProperSubsetOf(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.IsProperSubsetOf(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool IsProperSupersetOf(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.IsProperSupersetOf(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool IsSubsetOf(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.IsSubsetOf(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool IsSupersetOf(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.IsSupersetOf(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool Overlaps(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.Overlaps(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool SetEquals(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.SetEquals(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public void SymmetricExceptWith(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.SymmetricExceptWith(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public void UnionWith(IEnumerable<T> other)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.UnionWith(other);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         void ICollection<T>.Add(T item)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.Add(item);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public void Clear()
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.Clear();
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public bool Contains(T item)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.Contains(item);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public void CopyTo(T[] array, int arrayIndex)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 set.CopyTo(array, arrayIndex);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         void ICollection.CopyTo(Array array, int index)
@@ -167,11 +273,16 @@ namespace Lucene.Net.Support
 
                 try
                 {
-                    lock (SyncRoot)
+                    UninterruptableMonitor.Enter(SyncRoot);
+                    try
                     {
                         foreach (var item in set)
                             objects[index++] = item;
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(SyncRoot);
+                    }
                 }
                 catch (ArrayTypeMismatchException)
                 {
@@ -185,8 +296,15 @@ namespace Lucene.Net.Support
         {
             get
             {
-                lock (SyncRoot)
+                UninterruptableMonitor.Enter(SyncRoot);
+                try
+                {
                     return set.Count;
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(SyncRoot);
+                }
             }
         }
 
@@ -210,18 +328,30 @@ namespace Lucene.Net.Support
 
         public bool Remove(T item)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return set.Remove(item);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         public IEnumerator<T> GetEnumerator()
         {
             // Make a copy of the contents since enumeration is lazy and not thread-safe
             T[] array = new T[set.Count];
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
             {
                 set.CopyTo(array, 0);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
             return ((IEnumerable<T>)array).GetEnumerator();
         }
 
@@ -244,8 +374,15 @@ namespace Lucene.Net.Support
         /// <exception cref="ArgumentNullException">If <paramref name="comparer"/> is <c>null</c>.</exception>
         public bool Equals(object? other, IEqualityComparer comparer)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return JCG.SetEqualityComparer<T>.Equals(set, other, comparer);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         /// <summary>
@@ -257,8 +394,15 @@ namespace Lucene.Net.Support
         /// <returns>A hash code representing the current set.</returns>
         public int GetHashCode(IEqualityComparer comparer)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
+            {
                 return JCG.SetEqualityComparer<T>.GetHashCode(set, comparer);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         /// <summary>
@@ -301,13 +445,18 @@ namespace Lucene.Net.Support
         /// </exception>
         public string ToString(string? format, IFormatProvider? formatProvider)
         {
-            lock (SyncRoot)
+            UninterruptableMonitor.Enter(SyncRoot);
+            try
             {
                 if (set is IFormattable formattable)
                     return formattable.ToString(format ?? "{0}", formatProvider);
 
                 return string.Format(formatProvider, format ?? "{0}", set);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(SyncRoot);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net/Support/IO/StreamExtensions.cs b/src/Lucene.Net/Support/IO/StreamExtensions.cs
index f5b9fc0..e74c3d7 100644
--- a/src/Lucene.Net/Support/IO/StreamExtensions.cs
+++ b/src/Lucene.Net/Support/IO/StreamExtensions.cs
@@ -1,4 +1,5 @@
 using J2N.IO;
+using Lucene.Net.Support.Threading;
 using System;
 using System.IO;
 
@@ -81,7 +82,8 @@ namespace Lucene.Net.Support.IO
                 return 0;
 
             int read = 0;
-            lock (readLock)
+            UninterruptableMonitor.Enter(readLock);
+            try
             {
                 long originalPosition = stream.Position;
                 stream.Seek(position, SeekOrigin.Begin);
@@ -111,6 +113,10 @@ namespace Lucene.Net.Support.IO
                 // of the stream, so we return it as it was originally.
                 stream.Seek(originalPosition, SeekOrigin.Begin);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(readLock);
+            }
 
             return read;
         }
diff --git a/src/Lucene.Net/Support/Threading/LimitedConcurrencyLevelTaskScheduler.cs b/src/Lucene.Net/Support/Threading/LimitedConcurrencyLevelTaskScheduler.cs
index 3e26cf5..ce807e4 100644
--- a/src/Lucene.Net/Support/Threading/LimitedConcurrencyLevelTaskScheduler.cs
+++ b/src/Lucene.Net/Support/Threading/LimitedConcurrencyLevelTaskScheduler.cs
@@ -87,8 +87,9 @@ namespace Lucene.Net.Support.Threading
         protected sealed override void QueueTask(Task task)
         {
             // Add the task to the list of tasks to be processed.  If there aren't enough 
-            // delegates currently queued or running to process tasks, schedule another. 
-            lock (_tasks)
+            // delegates currently queued or running to process tasks, schedule another.
+            UninterruptableMonitor.Enter(_tasks);
+            try
             {
                 _tasks.AddLast(task);
                 if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
@@ -97,6 +98,10 @@ namespace Lucene.Net.Support.Threading
                     NotifyThreadPoolOfPendingWork();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(_tasks);
+            }
         }
 
         // Inform the ThreadPool that there's work to be executed for this scheduler. 
@@ -118,7 +123,8 @@ namespace Lucene.Net.Support.Threading
                     while (true)
                     {
                         Task item;
-                        lock (_tasks)
+                        UninterruptableMonitor.Enter(_tasks);
+                        try
                         {
                             // When there are no more items to be processed,
                             // note that we're done processing, and get out.
@@ -132,6 +138,10 @@ namespace Lucene.Net.Support.Threading
                             item = _tasks.First.Value;
                             _tasks.Remove(item);
                         }
+                        finally
+                        {
+                            UninterruptableMonitor.Exit(_tasks);
+                        }
 
                         // Execute the task we pulled out of the queue
                         base.TryExecuteTask(item);
@@ -162,7 +172,15 @@ namespace Lucene.Net.Support.Threading
         // Attempt to remove a previously scheduled task from the scheduler. 
         protected sealed override bool TryDequeue(Task task)
         {
-            lock (_tasks) return _tasks.Remove(task);
+            UninterruptableMonitor.Enter(_tasks);
+            try
+            {
+                return _tasks.Remove(task);
+            }
+            finally
+            {
+                UninterruptableMonitor.Exit(_tasks);
+            }
         }
 
         // Gets the maximum concurrency level supported by this scheduler. 
@@ -174,13 +192,13 @@ namespace Lucene.Net.Support.Threading
             bool lockTaken = false;
             try
             {
-                Monitor.TryEnter(_tasks, ref lockTaken);
+                UninterruptableMonitor.TryEnter(_tasks, ref lockTaken);
                 if (lockTaken) return _tasks;
                 else throw new NotSupportedException();
             }
             finally
             {
-                if (lockTaken) Monitor.Exit(_tasks);
+                if (lockTaken) UninterruptableMonitor.Exit(_tasks);
             }
         }
     }
diff --git a/src/Lucene.Net/Support/Threading/ReentrantLock.cs b/src/Lucene.Net/Support/Threading/ReentrantLock.cs
index 702a091..dd1359b 100644
--- a/src/Lucene.Net/Support/Threading/ReentrantLock.cs
+++ b/src/Lucene.Net/Support/Threading/ReentrantLock.cs
@@ -36,20 +36,20 @@ namespace Lucene.Net.Support.Threading
             // we enter the lock, then we immediately decrement it because that thread is no longer in the queue.
             // Due to race conditions, the queue length is an estimate only.
             Interlocked.Increment(ref _queueLength);
-            Monitor.Enter(_lock);
+            UninterruptableMonitor.Enter(_lock);
             Interlocked.Decrement(ref _queueLength);
         }
 
         // .NET Port: mimic ReentrantLock -- Monitor is re-entrant
         public void Unlock()
         {
-            Monitor.Exit(_lock);
+            UninterruptableMonitor.Exit(_lock);
         }
 
         public bool TryLock()
         {
             Interlocked.Increment(ref _queueLength);
-            bool success = Monitor.TryEnter(_lock);
+            bool success = UninterruptableMonitor.TryEnter(_lock);
             Interlocked.Decrement(ref _queueLength);
 
             return success;
@@ -69,6 +69,6 @@ namespace Lucene.Net.Support.Threading
 
         public bool HasQueuedThreads => _queueLength > 0;
 
-        public bool IsHeldByCurrentThread => Monitor.IsEntered(_lock);
+        public bool IsHeldByCurrentThread => UninterruptableMonitor.IsEntered(_lock);
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net/Util/AttributeSource.cs b/src/Lucene.Net/Util/AttributeSource.cs
index cda26f4..c4114c0 100644
--- a/src/Lucene.Net/Util/AttributeSource.cs
+++ b/src/Lucene.Net/Util/AttributeSource.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -111,7 +112,8 @@ namespace Lucene.Net.Util
 
                     // LUCENENET: If the weakreference is dead, we need to explicitly update its key.
                     // We synchronize on attClassImplMapLock to make the operation atomic.
-                    lock (attClassImplMapLock)
+                    UninterruptableMonitor.Enter(attClassImplMapLock);
+                    try
                     {
                         if (!attClassImplMap.TryGetValue(attClass, out var @ref) || !@ref.TryGetTarget(out clazz))
                         {
@@ -123,6 +125,10 @@ namespace Lucene.Net.Util
 #endif
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(attClassImplMapLock);
+                    }
 
                     return clazz;
                 }
diff --git a/src/Lucene.Net/Util/Fst/Util.cs b/src/Lucene.Net/Util/Fst/Util.cs
index 8e6c7b3..92bdf32 100644
--- a/src/Lucene.Net/Util/Fst/Util.cs
+++ b/src/Lucene.Net/Util/Fst/Util.cs
@@ -2,6 +2,7 @@
 using J2N.Numerics;
 using J2N.Text;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -441,10 +442,15 @@ namespace Lucene.Net.Util.Fst
                     // so we need to add some thread safety just in case.
                     // Perhaps it might make sense to wrap SortedSet into a type
                     // that provides thread safety.
-                    lock (syncLock)
+                    UninterruptableMonitor.Enter(syncLock);
+                    try
                     {
                         queue.Remove(queue.Max);
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(syncLock);
+                    }
                 }
             }
 
@@ -518,7 +524,8 @@ namespace Lucene.Net.Util.Fst
                     // so we need to add some thread safety just in case.
                     // Perhaps it might make sense to wrap SortedSet into a type
                     // that provides thread safety.
-                    lock (syncLock)
+                    UninterruptableMonitor.Enter(syncLock);
+                    try
                     {
                         path = queue.Min;
                         if (path != null)
@@ -526,6 +533,10 @@ namespace Lucene.Net.Util.Fst
                             queue.Remove(path);
                         }
                     }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(syncLock);
+                    }
 
                     if (path == null)
                     {
diff --git a/src/Lucene.Net/Util/InfoStream.cs b/src/Lucene.Net/Util/InfoStream.cs
index 7643ef5..243d66a 100644
--- a/src/Lucene.Net/Util/InfoStream.cs
+++ b/src/Lucene.Net/Util/InfoStream.cs
@@ -1,5 +1,6 @@
 using System;
 using Lucene.Net.Diagnostics;
+using Lucene.Net.Support.Threading;
 
 namespace Lucene.Net.Util
 {
@@ -68,20 +69,30 @@ namespace Lucene.Net.Util
         {
             get
             {
-                lock (typeof(InfoStream))
+                UninterruptableMonitor.Enter(typeof(InfoStream));
+                try
                 {
                     return defaultInfoStream;
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(typeof(InfoStream));
+                }
             }
             set
             {
-                lock (typeof(InfoStream))
+                UninterruptableMonitor.Enter(typeof(InfoStream));
+                try
                 {
                     defaultInfoStream = value ?? throw new ArgumentNullException(
                         nameof(Default),
                         "Cannot set InfoStream default implementation to null. " +
                         "To disable logging use InfoStream.NO_OUTPUT");
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(typeof(InfoStream));
+                }
             }
         }
 

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

Posted by ni...@apache.org.
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 152ffe658559f613afa3037467eea1165c261dee
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Thu Oct 14 20:42:02 2021 +0700

    SWEEP: Lucene.Net.TestFramework: Changed all lock statements to UninterruptableMonitor.Enter and UninterruptableMonitor.Exit to prevent ThreadInterruptedException from occurring when entering a lock.
---
 .../Analysis/BaseTokenStreamTestCase.cs            |   1 +
 .../Analysis/MockAnalyzer.cs                       |   8 +-
 .../Codecs/RAMOnly/RAMOnlyPostingsFormat.cs        |  17 +-
 .../Index/BaseMergePolicyTestCase.cs               |   8 +-
 .../Index/BasePostingsFormatTestCase.cs            |   7 +-
 .../Search/RandomSimilarityProvider.cs             |  15 +-
 .../Search/SearchEquivalenceTestBase.cs            |   7 +-
 .../Store/MockDirectoryWrapper.cs                  | 211 ++++++++++++++++++---
 .../Store/SlowClosingMockIndexInputWrapper.cs      |   3 +-
 .../Store/SlowOpeningMockIndexInputWrapper.cs      |   3 +-
 src/Lucene.Net.TestFramework/Util/LineFileDocs.cs  |  36 +++-
 .../Util/LuceneTestCase.cs                         |  28 ++-
 src/Lucene.Net.TestFramework/Util/TestUtil.cs      |   1 +
 .../Util/ThrottledIndexOutput.cs                   |   1 +
 14 files changed, 296 insertions(+), 50 deletions(-)

diff --git a/src/Lucene.Net.TestFramework/Analysis/BaseTokenStreamTestCase.cs b/src/Lucene.Net.TestFramework/Analysis/BaseTokenStreamTestCase.cs
index b26c20a..4e069df 100644
--- a/src/Lucene.Net.TestFramework/Analysis/BaseTokenStreamTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Analysis/BaseTokenStreamTestCase.cs
@@ -4,6 +4,7 @@ using Lucene.Net.Analysis.TokenAttributes;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using RandomizedTesting.Generators;
 using System;
diff --git a/src/Lucene.Net.TestFramework/Analysis/MockAnalyzer.cs b/src/Lucene.Net.TestFramework/Analysis/MockAnalyzer.cs
index a172ee0..cae547a 100644
--- a/src/Lucene.Net.TestFramework/Analysis/MockAnalyzer.cs
+++ b/src/Lucene.Net.TestFramework/Analysis/MockAnalyzer.cs
@@ -1,3 +1,4 @@
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using Lucene.Net.Util.Automaton;
 using System;
@@ -105,7 +106,8 @@ namespace Lucene.Net.Analysis
 
         private TokenFilter MaybePayload(TokenFilter stream, string fieldName)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 previousMappings.TryGetValue(fieldName, out int? val);
                 if (val == null)
@@ -155,6 +157,10 @@ namespace Lucene.Net.Analysis
                     return new MockFixedLengthPayloadFilter(random, stream, (int)val);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public void SetPositionIncrementGap(int positionIncrementGap)
diff --git a/src/Lucene.Net.TestFramework/Codecs/RAMOnly/RAMOnlyPostingsFormat.cs b/src/Lucene.Net.TestFramework/Codecs/RAMOnly/RAMOnlyPostingsFormat.cs
index 990f566..c5dc4f5 100644
--- a/src/Lucene.Net.TestFramework/Codecs/RAMOnly/RAMOnlyPostingsFormat.cs
+++ b/src/Lucene.Net.TestFramework/Codecs/RAMOnly/RAMOnlyPostingsFormat.cs
@@ -1,8 +1,9 @@
-using J2N.Text;
+using J2N.Text;
 using J2N.Threading.Atomic;
 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;
@@ -609,10 +610,15 @@ namespace Lucene.Net.Codecs.RAMOnly
             RAMPostings postings = new RAMPostings();
             RAMFieldsConsumer consumer = new RAMFieldsConsumer(postings);
 
-            lock (state)
+            UninterruptableMonitor.Enter(state);
+            try
             {
                 state[id] = postings;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(state);
+            }
             return consumer;
         }
 
@@ -641,10 +647,15 @@ namespace Lucene.Net.Codecs.RAMOnly
                 }
             }
 
-            lock (state)
+            UninterruptableMonitor.Enter(state);
+            try
             {
                 return state[id];
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(state);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net.TestFramework/Index/BaseMergePolicyTestCase.cs b/src/Lucene.Net.TestFramework/Index/BaseMergePolicyTestCase.cs
index ed3663f..9491259 100644
--- a/src/Lucene.Net.TestFramework/Index/BaseMergePolicyTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Index/BaseMergePolicyTestCase.cs
@@ -4,6 +4,7 @@ using Lucene.Net.Diagnostics;
 using Lucene.Net.Documents;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using RandomizedTesting.Generators;
 using System;
@@ -91,7 +92,8 @@ namespace Lucene.Net.Index
 
             public override void Merge(IndexWriter writer, MergeTrigger trigger, bool newMergesFound)
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (!mayMerge.Value && writer.NextMerge() != null)
                     {
@@ -99,6 +101,10 @@ namespace Lucene.Net.Index
                     }
                     base.Merge(writer, trigger, newMergesFound);
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
     }
diff --git a/src/Lucene.Net.TestFramework/Index/BasePostingsFormatTestCase.cs b/src/Lucene.Net.TestFramework/Index/BasePostingsFormatTestCase.cs
index 7af790a..5927d6e 100644
--- a/src/Lucene.Net.TestFramework/Index/BasePostingsFormatTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Index/BasePostingsFormatTestCase.cs
@@ -371,13 +371,18 @@ namespace Lucene.Net.Index
 //        //[Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.InheritanceBehavior.BeforeEachDerivedClass)]
 //        new public static void BeforeClass(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext context)
 //        {
-//            lock (initalizationLock)
+//            UninterruptableMonitor.Enter(initializationLock);
+//            try
 //            {
 //                if (!initalizationLock.Contains(context.FullyQualifiedTestClassName))
 //                    initalizationLock.Add(context.FullyQualifiedTestClassName);
 //                else
 //                    return; // Only allow this class to initialize once (MSTest bug)
 //            }
+//            finally
+//            {
+//                UninterruptableMonitor.Exit(initializationLock);
+//            }
 //#else
 #if TESTFRAMEWORK_NUNIT
         [NUnit.Framework.OneTimeSetUp]
diff --git a/src/Lucene.Net.TestFramework/Search/RandomSimilarityProvider.cs b/src/Lucene.Net.TestFramework/Search/RandomSimilarityProvider.cs
index 1d19759..2cf40a2 100644
--- a/src/Lucene.Net.TestFramework/Search/RandomSimilarityProvider.cs
+++ b/src/Lucene.Net.TestFramework/Search/RandomSimilarityProvider.cs
@@ -1,6 +1,7 @@
 using J2N.Collections.Generic.Extensions;
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Search.Similarities;
+using Lucene.Net.Support.Threading;
 using RandomizedTesting.Generators;
 using System;
 using System.Collections.Generic;
@@ -70,7 +71,8 @@ namespace Lucene.Net.Search
 
         public override Similarity Get(string field)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (Debugging.AssertsEnabled) Debugging.Assert(field != null);
                 if (!previousMappings.TryGetValue(field, out Similarity sim) || sim == null)
@@ -80,6 +82,10 @@ namespace Lucene.Net.Search
                 }
                 return sim;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // all the similarities that we rotate through
@@ -139,7 +145,8 @@ namespace Lucene.Net.Search
 
         public override string ToString()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 // LUCENENET: Use StringBuilder for better efficiency
                 var sb = new StringBuilder();
@@ -157,6 +164,10 @@ namespace Lucene.Net.Search
                 sb.AppendFormat(J2N.Text.StringFormatter.InvariantCulture, "{0}", previousMappings);
                 return sb.ToString();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/Lucene.Net.TestFramework/Search/SearchEquivalenceTestBase.cs b/src/Lucene.Net.TestFramework/Search/SearchEquivalenceTestBase.cs
index f2fb843..c846fda 100644
--- a/src/Lucene.Net.TestFramework/Search/SearchEquivalenceTestBase.cs
+++ b/src/Lucene.Net.TestFramework/Search/SearchEquivalenceTestBase.cs
@@ -64,13 +64,18 @@ namespace Lucene.Net.Search
 //        //[Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitialize(Microsoft.VisualStudio.TestTools.UnitTesting.InheritanceBehavior.BeforeEachDerivedClass)]
 //        new public static void BeforeClass(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext context)
 //        {
-//            lock (initalizationLock)
+//            UninterruptableMonitor.Enter(initializationLock);
+//            try
 //            {
 //                if (!initalizationLock.Contains(context.FullyQualifiedTestClassName))
 //                    initalizationLock.Add(context.FullyQualifiedTestClassName);
 //                else
 //                    return; // Only allow this class to initialize once (MSTest bug)
 //            }
+//            finally
+//            {
+//                UninterruptableMonitor.Exit(initializationLock);
+//            }
 //#else
 #if TESTFRAMEWORK_NUNIT
         [NUnit.Framework.OneTimeSetUp]
diff --git a/src/Lucene.Net.TestFramework/Store/MockDirectoryWrapper.cs b/src/Lucene.Net.TestFramework/Store/MockDirectoryWrapper.cs
index dd4be0a..aef6c3b 100644
--- a/src/Lucene.Net.TestFramework/Store/MockDirectoryWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/MockDirectoryWrapper.cs
@@ -4,6 +4,7 @@ using Lucene.Net.Diagnostics;
 using Lucene.Net.Index;
 using Lucene.Net.Index.Extensions;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using RandomizedTesting.Generators;
 using System;
@@ -135,7 +136,8 @@ namespace Lucene.Net.Store
 
         private void Init()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (openFiles == null)
                 {
@@ -152,6 +154,10 @@ namespace Lucene.Net.Store
                     unSyncedFiles = new JCG.HashSet<string>(StringComparer.Ordinal);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public MockDirectoryWrapper(Random random, Directory @delegate)
@@ -234,7 +240,8 @@ namespace Lucene.Net.Store
         [MethodImpl(MethodImplOptions.NoInlining)]
         public override void Sync(ICollection<string> names)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 MaybeThrowDeterministicException();
@@ -258,11 +265,16 @@ namespace Lucene.Net.Store
                     unSyncedFiles.ExceptWith(names);
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public long GetSizeInBytes()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (m_input is RAMDirectory ramDirectory)
                 {
@@ -279,6 +291,10 @@ namespace Lucene.Net.Store
                     return size;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -287,7 +303,8 @@ namespace Lucene.Net.Store
         /// </summary>
         public virtual void Crash()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 crashed = true;
                 openFiles = new Dictionary<string, int>(StringComparer.Ordinal);
@@ -387,15 +404,24 @@ namespace Lucene.Net.Store
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void ClearCrash()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 crashed = false;
                 openLocks.Clear();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual long MaxSizeInBytes
@@ -494,18 +520,24 @@ namespace Lucene.Net.Store
         [MethodImpl(MethodImplOptions.NoInlining)]
         public override void DeleteFile(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 DeleteFile(name, false);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // if there are any exceptions in OpenFileHandles
         // capture those as inner exceptions
         private Exception WithAdditionalErrorInformation(Exception t, string name, bool input)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 foreach (var ent in openFileHandles)
                 {
@@ -522,6 +554,10 @@ namespace Lucene.Net.Store
                 }
                 return t;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -541,7 +577,8 @@ namespace Lucene.Net.Store
         [MethodImpl(MethodImplOptions.NoInlining)]
         private void DeleteFile(string name, bool forced)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
 
@@ -578,14 +615,23 @@ namespace Lucene.Net.Store
                 }
                 m_input.DeleteFile(name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual ICollection<string> GetOpenDeletedFiles()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 return new JCG.HashSet<string>(openFilesDeleted, StringComparer.Ordinal);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool failOnCreateOutput = true;
@@ -598,7 +644,8 @@ namespace Lucene.Net.Store
 
         public override IndexOutput CreateOutput(string name, IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeThrowDeterministicException();
                 MaybeThrowIOExceptionOnOpen(name);
@@ -612,13 +659,18 @@ namespace Lucene.Net.Store
                     throw new IOException("cannot createOutput after crash");
                 }
                 Init();
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     if (preventDoubleWrite && createdFiles.Contains(name) && !name.Equals("segments.gen", StringComparison.Ordinal))
                     {
                         throw new IOException("file \"" + name + "\" was already written to");
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
                 if ((noDeleteOpenFile || assertNoDeleteOpenFile) && openFiles.ContainsKey(name))
                 {
                     if (!assertNoDeleteOpenFile)
@@ -683,6 +735,10 @@ namespace Lucene.Net.Store
                     return io;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal enum Handle
@@ -696,7 +752,8 @@ namespace Lucene.Net.Store
         {
             //Trace.TraceInformation("Add {0} {1}", c, name);
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (openFiles.TryGetValue(name, out int v))
                 {
@@ -712,6 +769,10 @@ namespace Lucene.Net.Store
 
                 openFileHandles[c] = RuntimeException.Create("unclosed Index" + handle.ToString() + ": " + name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         private bool failOnOpenInput = true;
@@ -724,7 +785,8 @@ namespace Lucene.Net.Store
 
         public override IndexInput OpenInput(string name, IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeThrowDeterministicException();
                 MaybeThrowIOExceptionOnOpen(name);
@@ -772,13 +834,18 @@ namespace Lucene.Net.Store
                 AddFileHandle(ii, name, Handle.Input);
                 return ii;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
         /// Provided for testing purposes.  Use <see cref="GetSizeInBytes()"/> instead. </summary>
         public long GetRecomputedSizeInBytes()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!(m_input is RAMDirectory))
                 {
@@ -791,6 +858,10 @@ namespace Lucene.Net.Store
                 }
                 return size;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -802,7 +873,8 @@ namespace Lucene.Net.Store
 
         public long GetRecomputedActualSizeInBytes()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (!(m_input is RAMDirectory))
                 {
@@ -815,6 +887,10 @@ namespace Lucene.Net.Store
                 }
                 return size;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // NOTE: this is off by default; see LUCENE-5574
@@ -843,7 +919,8 @@ namespace Lucene.Net.Store
 
         protected override void Dispose(bool disposing)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (disposing)
                 {
@@ -1024,13 +1101,18 @@ namespace Lucene.Net.Store
                     throttledOutput.Dispose(); // LUCENENET specific
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         internal virtual void RemoveOpenFile(IDisposable c, string name)
         {
             //Trace.TraceInformation("Rem {0} {1}", c, name);
 
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (openFiles.TryGetValue(name, out int v))
                 {
@@ -1049,23 +1131,37 @@ namespace Lucene.Net.Store
 
                 openFileHandles.TryRemove(c, out Exception _);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void RemoveIndexOutput(IndexOutput @out, string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 openFilesForWrite.Remove(name);
                 RemoveOpenFile(@out, name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public virtual void RemoveIndexInput(IndexInput @in, string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 RemoveOpenFile(@in, name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         // LUCENENET specific - de-nested Failure
@@ -1078,7 +1174,8 @@ namespace Lucene.Net.Store
         /// </summary>
         public virtual void FailOn(Failure fail)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (failures == null)
                 {
@@ -1086,6 +1183,10 @@ namespace Lucene.Net.Store
                 }
                 failures.Add(fail);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         /// <summary>
@@ -1094,7 +1195,8 @@ namespace Lucene.Net.Store
         /// </summary>
         internal virtual void MaybeThrowDeterministicException()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 if (failures != null)
                 {
@@ -1104,57 +1206,87 @@ namespace Lucene.Net.Store
                     }
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override string[] ListAll()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 return m_input.ListAll();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         [Obsolete("this method will be removed in 5.0")]
         public override bool FileExists(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 return m_input.FileExists(name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override long FileLength(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 return m_input.FileLength(name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override Lock MakeLock(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 return LockFactory.MakeLock(name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void ClearLock(string name)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 LockFactory.ClearLock(name);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void SetLockFactory(LockFactory lockFactory)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 // sneaky: we must pass the original this way to the dir, because
@@ -1163,13 +1295,18 @@ namespace Lucene.Net.Store
                 // now set our wrapped factory here
                 this.m_lockFactory = new MockLockFactoryWrapper(this, lockFactory);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override LockFactory LockFactory
         {
             get
             {
-                lock (this)
+                UninterruptableMonitor.Enter(this);
+                try
                 {
                     MaybeYield();
                     if (wrapLockFactory)
@@ -1181,26 +1318,40 @@ namespace Lucene.Net.Store
                         return m_input.LockFactory;
                     }
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(this);
+                }
             }
         }
 
         public override string GetLockID()
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 return m_input.GetLockID();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override void Copy(Directory to, string src, string dest, IOContext context)
         {
-            lock (this)
+            UninterruptableMonitor.Enter(this);
+            try
             {
                 MaybeYield();
                 // randomize the IOContext here?
                 m_input.Copy(to, src, dest, context);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(this);
+            }
         }
 
         public override IndexInputSlicer CreateSlicer(string name, IOContext context)
diff --git a/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs b/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
index c65685d..5af0dbe 100644
--- a/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
@@ -1,4 +1,5 @@
-using System;
+using Lucene.Net.Support.Threading;
+using System;
 using System.Threading;
 
 namespace Lucene.Net.Store
diff --git a/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs b/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
index 684e118..113c76c 100644
--- a/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
@@ -1,4 +1,5 @@
-using System;
+using Lucene.Net.Support.Threading;
+using System;
 using System.Threading;
 
 namespace Lucene.Net.Store
diff --git a/src/Lucene.Net.TestFramework/Util/LineFileDocs.cs b/src/Lucene.Net.TestFramework/Util/LineFileDocs.cs
index f81fe3e..79057d3 100644
--- a/src/Lucene.Net.TestFramework/Util/LineFileDocs.cs
+++ b/src/Lucene.Net.TestFramework/Util/LineFileDocs.cs
@@ -2,6 +2,7 @@
 using J2N.Threading.Atomic;
 using Lucene.Net.Documents;
 using Lucene.Net.Support.IO;
+using Lucene.Net.Support.Threading;
 using RandomizedTesting.Generators;
 using System;
 using System.Globalization;
@@ -70,7 +71,8 @@ namespace Lucene.Net.Util
 
         private void Close()
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 if (reader != null)
                 {
@@ -83,6 +85,10 @@ namespace Lucene.Net.Util
                     tempFilePath = null;
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private static Task DeleteAsync(string path)
@@ -111,11 +117,16 @@ namespace Lucene.Net.Util
         {
             if (disposing)
             {
-                lock (syncLock)
+                UninterruptableMonitor.Enter(syncLock);
+                try
                 {
                     Close();
                     threadDocs?.Dispose();
                 }
+                finally
+                {
+                    UninterruptableMonitor.Exit(syncLock);
+                }
             }
         }
 
@@ -145,7 +156,8 @@ namespace Lucene.Net.Util
 
         private void Open(Random random)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 Stream @is = null;
                 bool needSkip = true, isExternal = false;
@@ -232,16 +244,25 @@ namespace Lucene.Net.Util
                     reader.ReadLine();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         public virtual void Reset(Random random)
         {
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 Close();
                 Open(random);
                 id.Value = 0;
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
         }
 
         private const char SEP = '\t';
@@ -301,7 +322,8 @@ namespace Lucene.Net.Util
         public virtual Document NextDoc()
         {
             string line;
-            lock (syncLock)
+            UninterruptableMonitor.Enter(syncLock);
+            try
             {
                 line = reader.ReadLine();
                 if (line == null)
@@ -316,6 +338,10 @@ namespace Lucene.Net.Util
                     line = reader.ReadLine();
                 }
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(syncLock);
+            }
 
             DocState docState = threadDocs.Value;
             if (docState == null)
diff --git a/src/Lucene.Net.TestFramework/Util/LuceneTestCase.cs b/src/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
index fb9a072..f803a3a 100644
--- a/src/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
@@ -183,7 +183,8 @@ namespace Lucene.Net.Util
 
         public LuceneTestCase()
         {
-            lock (initalizationLock)
+            UninterruptableMonitor.Enter(initializationLock);
+            try
             {
                 var thisType = this.GetType();
                 if (!initalizationLock.Contains(thisType.FullName))
@@ -201,6 +202,10 @@ namespace Lucene.Net.Util
 
                 BeforeClass();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(initializationLock);
+            }
         }
 #else
     {
@@ -1050,7 +1055,8 @@ namespace Lucene.Net.Util
             if (context == null)
                 throw new ArgumentNullException(nameof(context));
 
-            lock (initalizationLock)
+            UninterruptableMonitor.Enter(initializationLock);
+            try
             {
                 if (!initalizationLock.Contains(context.FullyQualifiedTestClassName))
                     initalizationLock.Add(context.FullyQualifiedTestClassName);
@@ -1067,6 +1073,10 @@ namespace Lucene.Net.Util
                 _testClassType = Type.GetType(_testClassName);
 #endif
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(initializationLock);
+            }
 
             try
             {
@@ -3495,10 +3505,15 @@ namespace Lucene.Net.Util
                 Console.Error.WriteLine("INFO: Will leave temporary file: " + f.FullName);
                 return;
             }
-            lock (cleanupQueueLock)
+            UninterruptableMonitor.Enter(cleanupQueueLock);
+            try
             {
                 cleanupQueue.Push(f);
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(cleanupQueueLock);
+            }
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)]
@@ -3513,7 +3528,8 @@ namespace Lucene.Net.Util
             FileSystemInfo[] everything;
             string tempDirBasePath;
 
-            lock (cleanupQueueLock)
+            UninterruptableMonitor.Enter(cleanupQueueLock);
+            try
             {
                 tempDirBasePath = tempDirBase?.FullName;
                 tempDirBase = null;
@@ -3522,6 +3538,10 @@ namespace Lucene.Net.Util
                 everything = cleanupQueue.ToArray();
                 cleanupQueue.Clear();
             }
+            finally
+            {
+                UninterruptableMonitor.Exit(cleanupQueueLock);
+            }
 
             // LUCENENET specific - If the everything array is empty, there is no reason
             // to continue.
diff --git a/src/Lucene.Net.TestFramework/Util/TestUtil.cs b/src/Lucene.Net.TestFramework/Util/TestUtil.cs
index 2d880b9..9a774b6 100644
--- a/src/Lucene.Net.TestFramework/Util/TestUtil.cs
+++ b/src/Lucene.Net.TestFramework/Util/TestUtil.cs
@@ -864,6 +864,7 @@ namespace Lucene.Net.Util
         //    {
         //      try
         //      {
+        //        UninterruptableMonitor.RestoreInterrupt();
         //        ex.shutdown();
         //        ex.awaitTermination(1, TimeUnit.SECONDS);
         //      }
diff --git a/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs b/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
index 4892032..cf205f3 100644
--- a/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
+++ b/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Diagnostics;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
 using System;
 using System.Threading;
 

[lucenenet] 08/08: Lucene.Net.Tests.Index.TestIndexWriter: Removed [AwaitsFix] attribute from TestThreadInterruptDeadlock() and TestTwoThreadsInterruptDeadlock(), since they now are passing

Posted by ni...@apache.org.
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 3dcffb2929662ffb9c4678458eaf90f0df300f92
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Sun Oct 17 14:17:47 2021 +0700

    Lucene.Net.Tests.Index.TestIndexWriter: Removed [AwaitsFix] attribute from TestThreadInterruptDeadlock() and TestTwoThreadsInterruptDeadlock(), since they now are passing
---
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
index bc1b84e..ed87d16 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
@@ -1476,7 +1476,6 @@ namespace Lucene.Net.Index
 
         [Test]
         [Slow]
-        [AwaitsFix(BugUrl = "https://github.com/apache/lucenenet/issues/269")] // LUCENENET TODO: this test occasionally fails on .NET Core
         public virtual void TestThreadInterruptDeadlock()
         {
             IndexerThreadInterrupt t = new IndexerThreadInterrupt(this);
@@ -1517,7 +1516,6 @@ namespace Lucene.Net.Index
         /// testThreadInterruptDeadlock but with 2 indexer threads </summary>
         [Test]
         [Slow]
-        [AwaitsFix(BugUrl = "https://github.com/apache/lucenenet/issues/269")] // LUCENENET TODO: this test occasionally fails on .NET Core
         public virtual void TestTwoThreadsInterruptDeadlock()
         {
             IndexerThreadInterrupt t1 = new IndexerThreadInterrupt(this);

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

Posted by ni...@apache.org.
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;

[lucenenet] 02/08: SWEEP: Added Lucene.Net.Util.ThreadInterruptedException and re-throw it in all of the places that Lucene does.

Posted by ni...@apache.org.
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 b1e0eec678e3a345c807fa95999413065a93d07d
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Tue Mar 23 03:12:11 2021 +0700

    SWEEP: Added Lucene.Net.Util.ThreadInterruptedException and re-throw it in all of the places that Lucene does.
---
 .../ByTask/Feeds/EnwikiContentSource.cs            | 20 +++++--
 src/Lucene.Net.Replicator/ReplicationClient.cs     | 13 ++++-
 .../Store/SlowClosingMockIndexInputWrapper.cs      |  8 ++-
 .../Store/SlowOpeningMockIndexInputWrapper.cs      |  2 +-
 .../Util/ThrottledIndexOutput.cs                   | 13 ++++-
 src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs     | 10 +++-
 .../IndexAndTaxonomyReplicationClientTest.cs       | 10 +++-
 .../IndexReplicationClientTest.cs                  | 10 +++-
 .../Index/TestDocumentsWriterDeleteQueue.cs        | 13 +++--
 .../Index/TestDocumentsWriterStallControl.cs       |  4 +-
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs      | 34 ++++++++----
 .../Index/TestIndexWriterReader.cs                 | 14 ++++-
 .../Index/TestIndexWriterWithThreads.cs            | 10 +++-
 .../Index/TestSnapshotDeletionPolicy.cs            | 11 +++-
 .../Search/TestControlledRealTimeReopenThread.cs   | 14 +++--
 .../Search/TestTimeLimitingCollector.cs            | 12 +++-
 .../ExceptionHandling/TestExceptionExtensions.cs   |  2 +-
 src/Lucene.Net/Index/ConcurrentMergeScheduler.cs   | 32 +++++++----
 .../Index/DocumentsWriterFlushControl.cs           | 12 +++-
 .../Index/DocumentsWriterPerThreadPool.cs          | 10 +++-
 .../Index/DocumentsWriterStallControl.cs           | 24 +++++---
 src/Lucene.Net/Index/IndexWriter.cs                | 19 ++++---
 .../Search/ControlledRealTimeReopenThread.cs       | 20 +++++--
 src/Lucene.Net/Search/IndexSearcher.cs             |  3 +-
 src/Lucene.Net/Search/TimeLimitingCollector.cs     | 10 +++-
 src/Lucene.Net/Store/Lock.cs                       | 10 +++-
 src/Lucene.Net/Store/RateLimiter.cs                | 10 +++-
 .../ExceptionHandling/ExceptionExtensions.cs       | 10 +++-
 src/Lucene.Net/Util/ThreadInterruptedException.cs  | 64 ++++++++++++++++++++++
 29 files changed, 326 insertions(+), 98 deletions(-)

diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs b/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
index ce71b77..1e06701 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
@@ -77,8 +77,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 {
                     while (tuple == null && nmde == null && !threadDone && !stopped)
                     {
-                        Monitor.Wait(this);
-                        // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException. Note that it could be thrown above on lock (this).
+                        try
+                        {
+                            Monitor.Wait(this);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
                     if (tuple != null)
                     {
@@ -142,8 +148,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                             {
                                 while (tuple != null && !stopped)
                                 {
-                                    Monitor.Wait(this);
-                                    // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException. Note that it could be thrown above on lock (this).
+                                    try
+                                    {
+                                        Monitor.Wait(this); //wait();
+                                    }
+                                    catch (System.Threading.ThreadInterruptedException ie)
+                                    {
+                                        throw new Util.ThreadInterruptedException(ie);
+                                    }
                                 }
                                 tuple = tmpTuple;
                                 Monitor.Pulse(this); //notify();
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs b/src/Lucene.Net.Replicator/ReplicationClient.cs
index 51c07d5..e0c0164 100644
--- a/src/Lucene.Net.Replicator/ReplicationClient.cs
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -44,6 +44,8 @@ namespace Lucene.Net.Replicator
     /// </remarks>
     public class ReplicationClient : IDisposable
     {
+        // LUCENENET TODO: Check to ensure ThreadInterruptException is being passed from the background worker to the current thread, as it is required by IndexWriter
+
         //Note: LUCENENET specific, .NET does not work with Threads in the same way as Java does, so we mimic the same behavior using the ThreadPool instead.
         private class ReplicationThread
         {
@@ -430,7 +432,16 @@ namespace Lucene.Net.Replicator
             // otherwise, if it's in the middle of replication, we wait for it to
             // stop.
             if (updateThread != null)
-                updateThread.Stop();
+            {
+                try
+                {
+                    updateThread.Stop();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
+            }
             updateThread = null;
         }
 
diff --git a/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs b/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
index 5e047cb..c65685d 100644
--- a/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System;
+using System.Threading;
 
 namespace Lucene.Net.Store
 {
@@ -40,7 +41,10 @@ namespace Lucene.Net.Store
                 {
                     Thread.Sleep(50);
                 }
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
                 finally
                 {
                     base.Dispose(disposing);
diff --git a/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs b/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
index d6f7ef5..684e118 100644
--- a/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
@@ -42,7 +42,7 @@ namespace Lucene.Net.Store
                 catch (Exception ignore) when (ignore.IsThrowable())
                 {
                 }
-                throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                throw new Util.ThreadInterruptedException(ie);
             }
         }
     }
diff --git a/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs b/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
index 37590e2..4892032 100644
--- a/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
+++ b/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
@@ -142,9 +142,16 @@ namespace Lucene.Net.Util
                 return;
             }
 
-            Thread.Sleep(TimeSpan.FromMilliseconds(ms));
-            // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
-
+            try
+            {
+                Thread.Sleep(TimeSpan.FromMilliseconds(ms));
+            }
+            catch (Exception e) when (e.IsInterruptedException())
+            {
+#pragma warning disable IDE0001 // Simplify name
+                throw new Util.ThreadInterruptedException(e);
+#pragma warning restore IDE0001 // Simplify name
+            }
         }
 
         public override long Length
diff --git a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
index b293c99..40e98a6 100644
--- a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
+++ b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
@@ -77,8 +77,14 @@ namespace Lucene.Net.Facet
                 sTime = random.Next(sTime);
             }
 
-            Thread.Sleep(sTime);
-            // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+            try
+            {
+                Thread.Sleep(sTime);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                throw new Util.ThreadInterruptedException(ie);
+            }
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
index 6a43d60..d19a252 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -138,8 +138,14 @@ namespace Lucene.Net.Replicator
             // introducing timeouts is not good, can easily lead to false positives.
             while (client.IsUpdateThreadAlive)
             {
-                Thread.Sleep(100);
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException.
+                try
+                {
+                    Thread.Sleep(100);
+                }
+                catch (Exception e) when (e.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(e);
+                }
 
                 try
                 {
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
index 28450cf..de3040f 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -100,8 +100,14 @@ namespace Lucene.Net.Replicator
             while (client.IsUpdateThreadAlive)
             {
                 // give client a chance to update
-                Thread.Sleep(100);
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException.
+                try
+                {
+                    Thread.Sleep(100);
+                }
+                catch (Exception e) when (e.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(e);
+                }
 
                 try
                 {
diff --git a/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs b/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs
index 5daaa7d..593a618 100644
--- a/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs
+++ b/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs
@@ -1,4 +1,4 @@
-using J2N.Threading;
+using J2N.Threading;
 using J2N.Threading.Atomic;
 using Lucene.Net.Search;
 using Lucene.Net.Support.Threading;
@@ -318,9 +318,14 @@ namespace Lucene.Net.Index
 
             public override void Run()
             {
-
-                latch.Wait();
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                try
+                {
+                    latch.Wait();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
 
                 int i = 0;
                 while ((i = index.GetAndIncrement()) < ids.Length)
diff --git a/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs b/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
index 4f5dd18..3af2be4 100644
--- a/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
+++ b/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
@@ -275,7 +275,7 @@ namespace Lucene.Net.Index
                             catch (Exception e) when (e.IsInterruptedException())
                             {
                                 Console.WriteLine("[Waiter] got interrupted - wait count: " + sync.waiter.CurrentCount);
-                                throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                                throw new Util.ThreadInterruptedException(e);
                             }
                         }
                     }
@@ -330,7 +330,7 @@ namespace Lucene.Net.Index
                             catch (Exception e) when (e.IsInterruptedException())
                             {
                                 Console.WriteLine("[Updater] got interrupted - wait count: " + sync.waiter.CurrentCount);
-                                throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                                throw new Util.ThreadInterruptedException(e);
                             }
                             // LUCENENET: Not sure why this catch block was added, but I suspect it was for debugging purposes. Commented it rather than removing it because
                             // there may be some value to debugging this way.
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
index 05f1b09..ce37594 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
@@ -1316,7 +1316,7 @@ namespace Lucene.Net.Index
                             w.Dispose();
                             w = null;
                             //DirectoryReader.Open(dir).Dispose();
-                            using (var reader = DirectoryReader.Open(dir)) { }
+                            using var reader = DirectoryReader.Open(dir);
 
                             // Strangely, if we interrupt a thread before
                             // all classes are loaded, the class loader
@@ -1330,7 +1330,7 @@ namespace Lucene.Net.Index
                             allowInterrupt = true;
                         }
                     }
-                    catch (ThreadInterruptedException re) // LUCENENET: This was a custom wrapper type named ThreadInterruptedException in Lucene, so leaving the catch block as is
+                    catch (Util.ThreadInterruptedException re)
                     {
                         // NOTE: important to leave this verbosity/noise
                         // on!!  this test doesn't repro easily so when
@@ -1339,17 +1339,28 @@ namespace Lucene.Net.Index
                         Console.WriteLine("TEST: got interrupt");
                         Console.WriteLine(re.ToString());
 
-                        // LUCENENET NOTE: Since our original exception is ThreadInterruptException instead of InterruptException
-                        // in .NET, our expectation is typically that the InnerException is null (but it doesn't have to be).
-                        // So, this assertion is not needed in .NET. And if we get to this catch block, we already know we have
-                        // the right exception type, so there is nothing to test here.
-                        //Exception e = re.InnerException;
-                        //Assert.IsTrue(e is ThreadInterruptedException);
+                        Exception e = re.InnerException;
+                        Assert.IsTrue(e is System.Threading.ThreadInterruptedException);
                         if (finish)
                         {
                             break;
                         }
                     }
+                    //// LUCENENET specific:
+                    //catch (System.Threading.ThreadInterruptedException re)
+                    //{
+                    //    // NOTE: important to leave this verbosity/noise
+                    //    // on!!  this test doesn't repro easily so when
+                    //    // Jenkins hits a fail we need to study where the
+                    //    // interrupts struck!
+                    //    Console.WriteLine("TEST: got .NET interrupt");
+                    //    Console.WriteLine(re.ToString());
+
+                    //    if (finish)
+                    //    {
+                    //        break;
+                    //    }
+                    //}
                     catch (Exception t) when (t.IsThrowable())
                     {
                         Console.WriteLine("FAILED; unexpected exception");
@@ -1378,7 +1389,7 @@ namespace Lucene.Net.Index
                     {
                         Thread.Sleep(0);
                     }
-                    catch (ThreadInterruptedException)
+                    catch (Exception ie) when (ie.IsInterruptedException())
                     {
                         // ignore
                     }
@@ -1449,7 +1460,7 @@ namespace Lucene.Net.Index
             // up front... else we can see a false failure if 2nd
             // interrupt arrives while class loader is trying to
             // init this class (in servicing a first interrupt):
-            //Assert.IsTrue((new ThreadInterruptedException(new Exception("Thread interrupted"))).InnerException is ThreadInterruptedException);
+            Assert.IsTrue(new Util.ThreadInterruptedException(new System.Threading.ThreadInterruptedException()).InnerException is System.Threading.ThreadInterruptedException);
 
             // issue 300 interrupts to child thread
             int numInterrupts = AtLeast(300);
@@ -1494,8 +1505,7 @@ namespace Lucene.Net.Index
             // up front... else we can see a false failure if 2nd
             // interrupt arrives while class loader is trying to
             // init this class (in servicing a first interrupt):
-            // C# does not have the late load problem.
-            //Assert.IsTrue((new ThreadInterruptedException(new Exception("Thread interrupted"))).InnerException is ThreadInterruptedException);
+            Assert.IsTrue((new Util.ThreadInterruptedException(new System.Threading.ThreadInterruptedException())).InnerException is System.Threading.ThreadInterruptedException);
 
             // issue 300 interrupts to child thread
             int numInterrupts = AtLeast(300);
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
index b000cf5..9bd112c 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
@@ -508,12 +508,20 @@ namespace Lucene.Net.Index
             {
                 for (int i = 0; i < outerInstance.numThreads; i++)
                 {
-
-                    threads[i].Join();
-                    // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                    try
+                    {
+                        threads[i].Join();
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+#pragma warning disable IDE0001 // Simplify name
+                        throw new Util.ThreadInterruptedException(ie);
+#pragma warning restore IDE0001 // Simplify name
+                    }
                 }
             }
 
+
             internal virtual void Close(bool doWait)
             {
                 didClose = true;
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs b/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
index f9b0a71..65b6416 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
@@ -119,8 +119,14 @@ namespace Lucene.Net.Index
                         {
                             diskFull = true;
 
-                            Thread.Sleep(1);
-                            // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
+                            try
+                            {
+                                Thread.Sleep(1);
+                            }
+                            catch (Exception ie) when (ie.IsInterruptedException())
+                            {
+                                throw new Util.ThreadInterruptedException(ie);
+                            }
 
                             if (fullCount++ >= 5)
                             {
diff --git a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
index d330a09..ae923a1 100644
--- a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
+++ b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
@@ -226,9 +226,14 @@ namespace Lucene.Net.Index
                         }
                     }
 
-                    Thread.Sleep(1);
-                    // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
-
+                    try
+                    {
+                        Thread.Sleep(1);
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
                 } while (J2N.Time.NanoTime() / J2N.Time.MillisecondsPerNanosecond < stopTime); // LUCENENET: Use NanoTime() rather than CurrentTimeMilliseconds() for more accurate/reliable results
             }
         }
diff --git a/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs b/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
index 302377d..441605a 100644
--- a/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
@@ -521,12 +521,18 @@ namespace Lucene.Net.Search
             public override void UpdateDocument(Term term, IEnumerable<IIndexableField> doc, Analyzer analyzer)
             {
                 base.UpdateDocument(term, doc, analyzer);
-                if (waitAfterUpdate)
+                try
+                {
+                    if (waitAfterUpdate)
+                    {
+                        signal.Reset(signal.CurrentCount == 0 ? 0 : signal.CurrentCount - 1);
+                        latch.Wait();
+                    }
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
                 {
-                    signal.Reset(signal.CurrentCount == 0 ? 0 : signal.CurrentCount - 1);
-                    latch.Wait();
+                    throw new Util.ThreadInterruptedException(ie);
                 }
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
             }
         }
 
diff --git a/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs b/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
index 428855b..a41d341 100644
--- a/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
+++ b/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
@@ -401,8 +401,16 @@ namespace Lucene.Net.Search
                 int docId = doc + docBase;
                 if (slowdown > 0)
                 {
-                    ThreadJob.Sleep(slowdown);
-                    // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
+                    try
+                    {
+                        ThreadJob.Sleep(slowdown);
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+#pragma warning disable IDE0001 // Simplify name
+                        throw new Util.ThreadInterruptedException(ie);
+#pragma warning restore IDE0001 // Simplify name
+                    }
                 }
 
                 if (Debugging.AssertsEnabled) Debugging.Assert(docId >= 0," base={0} doc={1}", docBase, doc);
diff --git a/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs b/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs
index 628b09e..2a9257f 100644
--- a/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs
+++ b/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs
@@ -318,7 +318,7 @@ namespace Lucene
                 typeof(Lucene.UnsupportedOperationException),
 
                 // Corresponds to Lucene's ThreadInterruptedException
-                typeof(ThreadInterruptedException),
+                typeof(Lucene.Net.Util.ThreadInterruptedException),
 
                 // Corresponds to SecurityException
                 typeof(SecurityException),
diff --git a/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs b/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
index e873011..16c3b00 100644
--- a/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
+++ b/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
@@ -434,8 +434,14 @@ namespace Lucene.Net.Index
                         {
                             Message("    too many merges; stalling...");
                         }
-                        Monitor.Wait(this);
-                        // LUCENENET: Just let ThreadInterruptedException propagate. Note that it could be thrown above on lock (this).
+                        try
+                        {
+                            Monitor.Wait(this);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
 
                     if (IsVerbose)
@@ -690,15 +696,21 @@ namespace Lucene.Net.Index
         /// </summary>
         protected virtual void HandleMergeException(Exception exc)
         {
-            // When an exception is hit during merge, IndexWriter
-            // removes any partial files and then allows another
-            // merge to run.  If whatever caused the error is not
-            // transient then the exception will keep happening,
-            // so, we sleep here to avoid saturating CPU in such
-            // cases:
-            Thread.Sleep(250);
+            try
+            {
+                // When an exception is hit during merge, IndexWriter
+                // removes any partial files and then allows another
+                // merge to run.  If whatever caused the error is not
+                // transient then the exception will keep happening,
+                // so, we sleep here to avoid saturating CPU in such
+                // cases:
+                Thread.Sleep(250);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                throw new Util.ThreadInterruptedException(ie);
+            }
             throw new MergePolicy.MergeException(exc, m_dir);
-            // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
         }
 
         private bool suppressExceptions;
diff --git a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
index 8a23eac..124f8b7 100644
--- a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
@@ -309,12 +309,18 @@ namespace Lucene.Net.Index
 
         public void WaitForFlush()
         {
-             lock (this)
+            lock (this)
             {
                 while (flushingWriters.Count != 0)
                 {
-                    Monitor.Wait(this);
-                    // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                    try
+                    {
+                        Monitor.Wait(this);
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
                 }
             }
         }
diff --git a/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs b/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
index 10240f8..349af3c 100644
--- a/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
@@ -350,8 +350,14 @@ namespace Lucene.Net.Index
                     else
                     {
                         // Wait until a thread state frees up:
-                        Monitor.Wait(this);
-                        // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
+                        try
+                        {
+                            Monitor.Wait(this);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
                 }
             }
diff --git a/src/Lucene.Net/Index/DocumentsWriterStallControl.cs b/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
index 77303bc..fad1ab4 100644
--- a/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
@@ -1,6 +1,7 @@
 using J2N.Runtime.CompilerServices;
 using J2N.Threading;
 using Lucene.Net.Diagnostics;
+using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Threading;
@@ -81,15 +82,20 @@ namespace Lucene.Net.Index
                     if (stalled) // react on the first wakeup call!
                     {
                         // don't loop here, higher level logic will re-stall!
-
-                        // LUCENENET: make sure not to run IncWaiters / DecrWaiters in Debugging.Assert as that gets 
-                        // disabled in production
-                        var result = IncWaiters();
-                        if (Debugging.AssertsEnabled) Debugging.Assert(result);
-                        Monitor.Wait(this);
-                        result = DecrWaiters();
-                        if (Debugging.AssertsEnabled) Debugging.Assert(result);
-                        // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                        try
+                        {
+                            // LUCENENET: make sure not to run IncWaiters / DecrWaiters in Debugging.Assert as that gets 
+                            // disabled in production
+                            var result = IncWaiters();
+                            if (Debugging.AssertsEnabled) Debugging.Assert(result);
+                            Monitor.Wait(this);
+                            result = DecrWaiters();
+                            if (Debugging.AssertsEnabled) Debugging.Assert(result);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
                 }
             }
diff --git a/src/Lucene.Net/Index/IndexWriter.cs b/src/Lucene.Net/Index/IndexWriter.cs
index 5daf4ba..adda7ea 100644
--- a/src/Lucene.Net/Index/IndexWriter.cs
+++ b/src/Lucene.Net/Index/IndexWriter.cs
@@ -157,8 +157,8 @@ namespace Lucene.Net.Index
     /// <para><b>NOTE</b>: If you call
     /// <see cref="Thread.Interrupt()"/> on a thread that's within
     /// <see cref="IndexWriter"/>, <see cref="IndexWriter"/> will try to catch this (eg, if
-    /// it's in a Wait() or <see cref="Thread.Sleep(int)"/>), and will then throw
-    /// the unchecked exception <see cref="ThreadInterruptedException"/>
+    /// it's in a <see cref="Monitor.Wait(object)"/> or <see cref="Thread.Sleep(int)"/>), and will then throw
+    /// the unchecked exception <see cref="Util.ThreadInterruptedException"/>
     /// and <b>clear</b> the interrupt status on the thread.</para>
     /// </remarks>
 
@@ -1178,7 +1178,7 @@ namespace Lucene.Net.Index
                                 // any pending merges are waiting:
                                 mergeScheduler.Merge(this, MergeTrigger.CLOSING, false);
                             }
-                            catch (ThreadInterruptedException) // LUCENENET: In Lucene, they caught their custom ThreadInterruptedException here, so we are leaving this catch block as is
+                            catch (Util.ThreadInterruptedException)
                             {
                                 // ignore any interruption, does not matter
                                 interrupted = true;
@@ -1198,7 +1198,7 @@ namespace Lucene.Net.Index
                                     FinishMerges(waitForMerges && !interrupted);
                                     break;
                                 }
-                                catch (ThreadInterruptedException) // LUCENENET: In Lucene, they caught their custom ThreadInterruptedException here, so we are leaving this catch block as is
+                                catch (Util.ThreadInterruptedException)
                                 {
                                     // by setting the interrupted status, the
                                     // next call to finishMerges will pass false,
@@ -5329,9 +5329,14 @@ namespace Lucene.Net.Index
                 // fails to be called, we wait for at most 1 second
                 // and then return so caller can check if wait
                 // conditions are satisfied:
-
-                Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                try
+                {
+                    Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs b/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
index 961ea84..954c018 100644
--- a/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
@@ -135,13 +135,21 @@ namespace Lucene.Net.Search
             {
                 finish = true;
                 reopenCond.Set();
-                
-                Join();
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
 
-                // LUCENENET specific: dispose reset event
-                reopenCond.Dispose();
-                available.Dispose();
+                try
+                {
+                    Join();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
+                finally
+                {
+                    // LUCENENET specific: dispose reset event
+                    reopenCond.Dispose();
+                    available.Dispose();
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Search/IndexSearcher.cs b/src/Lucene.Net/Search/IndexSearcher.cs
index 50e9213..f76d991 100644
--- a/src/Lucene.Net/Search/IndexSearcher.cs
+++ b/src/Lucene.Net/Search/IndexSearcher.cs
@@ -880,8 +880,7 @@ namespace Lucene.Net.Search
                     }
                     catch (Exception e) when (e.IsInterruptedException())
                     {
-                        // LUCENENET: Throwing as same type, no need to wrap here
-                        throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                        throw new Util.ThreadInterruptedException(e);
                     }
                     catch (Exception e)
                     {
diff --git a/src/Lucene.Net/Search/TimeLimitingCollector.cs b/src/Lucene.Net/Search/TimeLimitingCollector.cs
index 651d983..4549503 100644
--- a/src/Lucene.Net/Search/TimeLimitingCollector.cs
+++ b/src/Lucene.Net/Search/TimeLimitingCollector.cs
@@ -304,8 +304,14 @@ namespace Lucene.Net.Search
                     // TODO: Use System.nanoTime() when Lucene moves to Java SE 5.
                     counter.AddAndGet(resolution);
 
-                    Thread.Sleep(TimeSpan.FromMilliseconds(Interlocked.Read(ref resolution)));
-                    // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException 
+                    try
+                    {
+                        Thread.Sleep(TimeSpan.FromMilliseconds(Interlocked.Read(ref resolution)));
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
                 }
             }
 
diff --git a/src/Lucene.Net/Store/Lock.cs b/src/Lucene.Net/Store/Lock.cs
index 4ee94d0..0f9d167 100644
--- a/src/Lucene.Net/Store/Lock.cs
+++ b/src/Lucene.Net/Store/Lock.cs
@@ -136,8 +136,14 @@ namespace Lucene.Net.Store
                     throw e;
                 }
 
-                Thread.Sleep(TimeSpan.FromMilliseconds(LOCK_POLL_INTERVAL));
-                // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
+                try
+                {
+                    Thread.Sleep(TimeSpan.FromMilliseconds(LOCK_POLL_INTERVAL));
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
 
                 locked = Obtain();
             }
diff --git a/src/Lucene.Net/Store/RateLimiter.cs b/src/Lucene.Net/Store/RateLimiter.cs
index df7ccd0..61e2339 100644
--- a/src/Lucene.Net/Store/RateLimiter.cs
+++ b/src/Lucene.Net/Store/RateLimiter.cs
@@ -120,8 +120,14 @@ namespace Lucene.Net.Store
                     var pauseNS = targetNS - curNS;
                     if (pauseNS > 0)
                     {
-                        Thread.Sleep(TimeSpan.FromMilliseconds(pauseNS / 1000000));
-                        // LUCENENET NOTE: No need to catch and rethrow same excepton type ThreadInterruptedException
+                        try
+                        {
+                            Thread.Sleep(TimeSpan.FromMilliseconds(pauseNS / 1000000));
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
 
                         curNS = Time.NanoTime();
                         continue;
diff --git a/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs b/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
index 3795b7a..5a25bf6 100644
--- a/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
+++ b/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
@@ -155,6 +155,10 @@ namespace Lucene
                 // .NET made IOException a SystemExcpetion, but those should not be included here
                 e.IsIOException() ||
 
+                // .NET made System.Threading.ThreadInterruptedException a SystemException, but we need to ignore it
+                // because InterruptedException in Java subclasses Exception, not RuntimeException
+                e is System.Threading.ThreadInterruptedException ||
+
                 // ObjectDisposedException is a special case because in Lucene the AlreadyClosedException derived
                 // from IOException and was therefore a checked excpetion type.
                 e is ObjectDisposedException ||
@@ -448,10 +452,10 @@ namespace Lucene
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsInterruptedException(this Exception e)
         {
-            // LUCENENET: Special case - we only catch under certain scenarios and do not rethrow explicitly.
             // This exception is the shutdown signal for a thread and it is used in Lucene for control flow.
-            // However, in .NET it is thrown in more cases than in Java. So, rather than wrapping it in a new
-            // exception type, we don't catch it unless there is a specific reason to do something other than re-throw.
+            // Lucene uses a custom Lucene.Net.Util.ThreadInterruptedException exception to handle the signal.
+            // It is only thrown from certain blocks, and we use UninterruptableMonitor.Enter() to avoid getting
+            // the System.Threading.ThreadInterruptedException when obtaining locks.
             return e is ThreadInterruptedException;
         }
 
diff --git a/src/Lucene.Net/Util/ThreadInterruptedException.cs b/src/Lucene.Net/Util/ThreadInterruptedException.cs
new file mode 100644
index 0000000..85dbc89
--- /dev/null
+++ b/src/Lucene.Net/Util/ThreadInterruptedException.cs
@@ -0,0 +1,64 @@
+using System;
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+using System.Runtime.Serialization;
+#endif
+
+namespace Lucene.Net.Util
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    /// <summary>
+    /// Thrown by Lucene on detecing that <see cref="System.Threading.Thread.Interrupt()"/> had been
+    /// called. This exception has the specific purpose of being allowed to pass through to the
+    /// calling thread of <see cref="J2N.Threading.ThreadJob"/> so it reaches the appropriate handler.
+    /// </summary>
+    // LUCENENET: In Lucene, this exception was so it could be re-thrown unchecked. It has been
+    // re-purposed in .NET but used in all the same scenerios.
+    // LUCENENET: It is no longer good practice to use binary serialization. 
+    // See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+    [Serializable]
+#endif
+    public class ThreadInterruptedException : Exception, IRuntimeException
+    {
+        public ThreadInterruptedException(Exception interruptedException)
+            : base(interruptedException.Message, interruptedException)
+        {
+        }
+
+        public ThreadInterruptedException(string message) : base(message)
+        {
+        }
+
+        public ThreadInterruptedException(string message, Exception innerException) : base(message, innerException)
+        {
+        }
+
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+        /// <summary>
+        /// Initializes a new instance of this class with serialized data.
+        /// </summary>
+        /// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
+        /// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
+        protected ThreadInterruptedException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+        }
+#endif
+    }
+}

[lucenenet] 03/08: Lucene.Net.Support.Threading: Created UninterruptableMonitor class to handle entering locks without throwing System.Threading.ThreadInterruptedException (which is what happens in Java)

Posted by ni...@apache.org.
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 dd89a4fcf42f76c54c44c2decae8b4811c6e43e5
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Wed Oct 13 12:35:13 2021 +0700

    Lucene.Net.Support.Threading: Created UninterruptableMonitor class to handle entering locks without throwing System.Threading.ThreadInterruptedException (which is what happens in Java)
---
 .../Threading/TestUninterruptableMonitor.cs        | 313 +++++++++++++++++++++
 .../Support/Threading/UninterruptableMonitor.cs    | 167 +++++++++++
 2 files changed, 480 insertions(+)

diff --git a/src/Lucene.Net.Tests/Support/Threading/TestUninterruptableMonitor.cs b/src/Lucene.Net.Tests/Support/Threading/TestUninterruptableMonitor.cs
new file mode 100644
index 0000000..8da4b04
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/Threading/TestUninterruptableMonitor.cs
@@ -0,0 +1,313 @@
+using J2N.Threading;
+using J2N.Threading.Atomic;
+using Lucene.Net.Attributes;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using RandomizedTesting.Generators;
+using System;
+using System.Threading;
+using Assert = Lucene.Net.TestFramework.Assert;
+
+namespace Lucene.Net.Support
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    [TestFixture]
+    public class TestUninterruptableMonitor : LuceneTestCase
+    {
+        private class TransactionlThreadInterrupt : ThreadJob
+        {
+            private static AtomicInt32 transactionNumber = new AtomicInt32(0);
+
+            // Share locks between threads
+            private static readonly object lock1 = new object();
+            private static readonly object lock2 = new object();
+            private static readonly object lock3 = new object();
+
+            internal volatile bool failed;
+            internal volatile bool finish;
+
+            internal volatile bool allowInterrupt = false;
+            internal volatile bool transactionInProgress = false;
+            
+
+            public override void Run()
+            {
+                while (!finish)
+                {
+                    try
+                    {
+                        TransactionalMethod();
+                        TransactionalMethod();
+                        InterruptableMethod();
+                        TransactionalMethod();
+                        InterruptableMethod();
+
+                        // Make sure these don't throw System.Threading.ThreadInterruptedException
+                        Assert.IsFalse(UninterruptableMonitor.IsEntered(lock1));
+                        Assert.IsFalse(UninterruptableMonitor.IsEntered(lock2));
+                        Assert.IsFalse(UninterruptableMonitor.IsEntered(lock3));
+
+                        if (UninterruptableMonitor.TryEnter(lock1))
+                        {
+                            try
+                            {
+                                Assert.IsTrue(UninterruptableMonitor.IsEntered(lock1));
+                            }
+                            finally
+                            {
+                                UninterruptableMonitor.Exit(lock1);
+                            }
+                        }
+
+                        allowInterrupt = true;
+                    }
+                    catch (Util.ThreadInterruptedException re)
+                    {
+                        // Success - we received the correct exception type
+                        Console.WriteLine("TEST: got interrupt");
+                        Console.WriteLine(GetToStringFrom(re));
+
+                        Exception e = re.InnerException;
+                        Assert.IsTrue(e is System.Threading.ThreadInterruptedException);
+
+                        // Make sure we didn't interrupt in the middle of a transaction
+                        Assert.IsFalse(transactionInProgress);
+
+                        if (finish)
+                        {
+                            break;
+                        }
+                    }
+                    catch (Exception t) when (t.IsThrowable())
+                    {
+                        Console.WriteLine("FAILED; unexpected exception");
+                        Console.WriteLine(GetToStringFrom(t));
+
+                        // Make sure we didn't error in the middle of a transaction
+                        Assert.IsFalse(transactionInProgress);
+
+                        failed = true;
+                        break;
+                    }
+                }
+            }
+
+
+            private void TransactionalMethod()
+            {
+                Assert.IsFalse(transactionInProgress, "The prior transaction failed to complete (was interrupted).");
+                transactionInProgress = true;
+                int transactionId = transactionNumber.IncrementAndGet();
+                if (Verbose)
+                {
+                    Console.WriteLine($"transaction STARTED: {transactionId}");
+                }
+
+                // Nested lock test
+                UninterruptableMonitor.Enter(lock1);
+                try
+                {
+                    if (Verbose)
+                    {
+                        Console.WriteLine("acquired lock1 successfully");
+                        Console.WriteLine("sleeping...");
+                    }
+
+                    // Use SpinWait instead of Sleep to demonstrate the 
+                    // effect of calling Interrupt on a running thread.
+                    Thread.SpinWait(1000000);
+
+                    UninterruptableMonitor.Enter(lock2);
+                    try
+                    {
+                        if (Verbose)
+                        {
+                            Console.WriteLine("acquired lock2 successfully");
+                            Console.WriteLine("sleeping...");
+                        }
+
+                        // Use SpinWait instead of Sleep to demonstrate the 
+                        // effect of calling Interrupt on a running thread.
+                        Thread.SpinWait(1000000);
+                    }
+                    finally
+                    {
+                        UninterruptableMonitor.Exit(lock2);
+                    }
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(lock1);
+                }
+
+                // inline lock test
+                UninterruptableMonitor.Enter(lock3);
+                try
+                {
+                    if (Verbose)
+                    {
+                        Console.WriteLine("acquired lock3 successfully");
+                        Console.WriteLine("sleeping...");
+                    }
+
+                    // Use SpinWait instead of Sleep to demonstrate the 
+                    // effect of calling Interrupt on a running thread.
+                    Thread.SpinWait(1000000);
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(lock3);
+                }
+
+                if (Verbose)
+                {
+                    Console.WriteLine($"transaction COMPLETED: {transactionId}");
+                }
+
+                transactionInProgress = false;
+            }
+
+            private void InterruptableMethod()
+            {
+                UninterruptableMonitor.Enter(lock1);
+                try
+                {
+                    if (Verbose)
+                    {
+                        Console.WriteLine("acquired lock1 successfully");
+                        Console.WriteLine("sleeping...");
+                    }
+
+                    try
+                    {
+                        UninterruptableMonitor.Wait(lock1, TimeSpan.FromMilliseconds(200));
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
+                }
+                finally
+                {
+                    UninterruptableMonitor.Exit(lock1);
+                }
+            }
+
+            /// <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, LuceneNetSpecific]
+        [Slow]
+        public virtual void TestThreadInterrupt()
+        {
+            TransactionlThreadInterrupt t = new TransactionlThreadInterrupt();
+            t.IsBackground = (true);
+            t.Start();
+
+            // issue 300 interrupts to child thread
+            int numInterrupts = AtLeast(300);
+            int i = 0;
+            while (i < numInterrupts)
+            {
+                // TODO: would be nice to also sometimes interrupt the
+                // CMS merge threads too ...
+                Thread.Sleep(10);
+                if (t.allowInterrupt)
+                {
+                    i++;
+                    t.Interrupt();
+                }
+                if (!t.IsAlive)
+                {
+                    break;
+                }
+            }
+            t.finish = true;
+            t.Join();
+
+            Assert.IsFalse(t.failed);
+            Assert.IsFalse(t.transactionInProgress);
+        }
+
+        [Test, LuceneNetSpecific]
+        [Slow]
+        public virtual void TestTwoThreadsInterrupt()
+        {
+            TransactionlThreadInterrupt t1 = new TransactionlThreadInterrupt();
+            t1.IsBackground = (true);
+            t1.Start();
+
+            TransactionlThreadInterrupt t2 = new TransactionlThreadInterrupt();
+            t2.IsBackground = (true);
+            t2.Start();
+
+            // issue 300 interrupts to child thread
+            int numInterrupts = AtLeast(300);
+            int i = 0;
+            while (i < numInterrupts)
+            {
+                // TODO: would be nice to also sometimes interrupt the
+                // CMS merge threads too ...
+                Thread.Sleep(10);
+                TransactionlThreadInterrupt t = Random.NextBoolean() ? t1 : t2;
+                if (t.allowInterrupt)
+                {
+                    i++;
+                    t.Interrupt();
+                }
+                if (!t1.IsAlive && !t2.IsAlive)
+                {
+                    break;
+                }
+            }
+            t1.finish = true;
+            t2.finish = true;
+            t1.Join();
+            t2.Join();
+
+            Assert.IsFalse(t1.failed);
+            Assert.IsFalse(t2.failed);
+            Assert.IsFalse(t1.transactionInProgress);
+            Assert.IsFalse(t2.transactionInProgress);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Lucene.Net/Support/Threading/UninterruptableMonitor.cs b/src/Lucene.Net/Support/Threading/UninterruptableMonitor.cs
new file mode 100644
index 0000000..d145f13
--- /dev/null
+++ b/src/Lucene.Net/Support/Threading/UninterruptableMonitor.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Threading;
+
+namespace Lucene.Net.Support.Threading
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    /// <summary>
+    /// A drop-in replacement for <see cref="Monitor"/> that doesn't throw <see cref="ThreadInterruptedException"/>
+    /// when entering locks, but defers the excepetion until a wait or sleep occurs. This is to mimic the behavior in Java,
+    /// which does not throw when entering a lock.
+    /// </summary>
+    internal static class UninterruptableMonitor
+    {
+        public static void Enter(object obj, ref bool lockTaken)
+        {
+            // enter the lock and ignore any System.Threading.ThreadInterruptedException
+            try
+            {
+                Monitor.Enter(obj, ref lockTaken);
+            }
+            catch (Exception ie) when(ie.IsInterruptedException())
+            {
+                RetryEnter(obj, ref lockTaken);
+
+                // The lock has been obtained, now reset the interrupted status for the
+                // current thread
+                Thread.CurrentThread.Interrupt();
+            }
+        }
+
+        private static void RetryEnter(object obj, ref bool lockTaken)
+        {
+            try
+            {
+                // An interrupted exception may have already cleared the flag, and this will succeed without any more excpetions
+                Monitor.Enter(obj, ref lockTaken);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                // try again until we succeed, since an interrupt could have happened since it was cleared
+                RetryEnter(obj, ref lockTaken);
+            }
+        }
+
+        public static void Enter(object obj)
+        {
+            // enter the lock and ignore any System.Threading.ThreadInterruptedException
+            try
+            {
+                Monitor.Enter(obj);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                RetryEnter(obj);
+
+                // The lock has been obtained, now reset the interrupted status for the
+                // current thread
+                Thread.CurrentThread.Interrupt();
+            }
+        }
+
+        private static void RetryEnter(object obj)
+        {
+            try
+            {
+                // An interrupted exception may have already cleared the flag, and this will succeed without any more excpetions
+                Monitor.Enter(obj);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                // try again until we succeed, since an interrupt could have happened since it was cleared
+                RetryEnter(obj);
+            }
+        }
+
+        public static void Exit(object obj)
+        {
+            Monitor.Exit(obj);
+        }
+
+        public static bool IsEntered(object obj)
+        {
+            return Monitor.IsEntered(obj);
+        }
+
+        public static bool TryEnter(object obj)
+        {
+            return Monitor.TryEnter(obj);
+        }
+
+        public static void TryEnter(object obj, ref bool lockTaken)
+        {
+            Monitor.TryEnter(obj, ref lockTaken);
+        }
+
+        public static bool TryEnter(object obj, int millisecondsTimeout)
+        {
+            return Monitor.TryEnter(obj, millisecondsTimeout);
+        }
+
+        public static bool TryEnter(object obj, TimeSpan timeout)
+        {
+            return Monitor.TryEnter(obj, timeout);
+        }
+
+        public static void TryEnter(object obj, int millisecondsTimeout, ref bool lockTaken)
+        {
+            Monitor.TryEnter(obj, millisecondsTimeout, ref lockTaken);
+        }
+
+        public static void TryEnter(object obj, TimeSpan timeout, ref bool lockTaken)
+        {
+            Monitor.TryEnter(obj, timeout, ref lockTaken);
+        }
+
+        public static void Pulse(object obj)
+        {
+            Monitor.Pulse(obj);
+        }
+
+        public static void PulseAll(object obj)
+        {
+            Monitor.PulseAll(obj);
+        }
+
+        public static void Wait(object obj)
+        {
+            Monitor.Wait(obj);
+        }
+
+        public static void Wait(object obj, int millisecondsTimeout)
+        {
+            Monitor.Wait(obj, millisecondsTimeout);
+        }
+
+        public static void Wait(object obj, TimeSpan timeout)
+        {
+            Monitor.Wait(obj, timeout);
+        }
+
+        public static void Wait(object obj, int millisecondsTimeout, bool exitContext)
+        {
+            Monitor.Wait(obj, millisecondsTimeout, exitContext);
+        }
+
+        public static void Wait(object obj, TimeSpan timeout, bool exitContext)
+        {
+            Monitor.Wait(obj, timeout, exitContext);
+        }
+    }
+}