Buggy code:
@ SuppressCodecs ( "Lucene3x" ) public class TestDocValuesWithThreads extends LuceneTestCase { public void test ( ) throws Exception { Directory dir = newDirectory ( ) ; IndexWriter w = new IndexWriter ( dir , newIndexWriterConfig ( TEST_VERSION_CURRENT , new org . apache . lucene . analysis . MockAnalyzer ( random ( ) ) ) . setMergePolicy ( newLogMergePolicy ( ) ) ) ; final List < Long > numbers = new ArrayList < Long > ( ) ; final List < BytesRef > binary = new ArrayList < BytesRef > ( ) ; final List < BytesRef > sorted = new ArrayList < BytesRef > ( ) ; final int numDocs = atLeast ( 100 ) ; for ( int i = 0 ; i < numDocs ; i ++ ) { Document d = new Document ( ) ; long number = random ( ) . nextLong ( ) ; d . add ( new NumericDocValuesField ( "number" , number ) ) ; BytesRef bytes = new BytesRef ( _TestUtil . randomRealisticUnicodeString ( random ( ) ) ) ; d . add ( new org . apache . lucene . document . BinaryDocValuesField ( "bytes" , bytes ) ) ; binary . add ( bytes ) ; bytes = new BytesRef ( _TestUtil . randomRealisticUnicodeString ( random ( ) ) ) ; d . add ( new org . apache . lucene . document . SortedDocValuesField ( "sorted" , bytes ) ) ; sorted . add ( bytes ) ; w . addDocument ( d ) ; numbers . add ( number ) ; } w . forceMerge ( 1 ) ; final IndexReader r = w . getReader ( ) ; w . close ( ) ; assertEquals ( 1 , r . leaves ( ) . size ( ) ) ; final AtomicReader ar = r . leaves ( ) . get ( 0 ) . reader ( ) ; int numThreads = _TestUtil . nextInt ( random ( ) , 2 , 5 ) ; List < Thread > threads = new ArrayList < Thread > ( ) ; final CountDownLatch startingGun = new CountDownLatch ( 1 ) ; for ( int t = 0 ; t < numThreads ; t ++ ) { final Random threadRandom = new Random ( random ( ) . nextLong ( ) ) ; Thread thread = new Thread ( ) { @ Override public void run ( ) { try { FieldCache . Longs ndv = DEFAULT . getLongs ( ar , "number" , false ) ; <START_BUG> BinaryDocValues bdv = DEFAULT . getTerms ( ar , "bytes" ) ; <END_BUG> SortedDocValues sdv = DEFAULT . getTermsIndex ( ar , "sorted" ) ; startingGun . await ( ) ; int iters = atLeast ( 1000 ) ; BytesRef scratch = new BytesRef ( ) ; BytesRef scratch2 = new BytesRef ( ) ; for ( int iter = 0 ; iter < iters ; iter ++ ) { int docID = threadRandom . nextInt ( numDocs ) ; switch ( threadRandom . nextInt ( 6 ) ) { case 0 : assertEquals ( ( ( byte ) ( numbers . get ( docID ) . longValue ( ) ) ) , DEFAULT . getBytes ( ar , "number" , false ) . get ( docID ) ) ; break ; case 1 : assertEquals ( ( ( short ) ( numbers . get ( docID ) . longValue ( ) ) ) , DEFAULT . getShorts ( ar , "number" , false ) . get ( docID ) ) ; break ; case 2 : assertEquals ( ( ( int ) ( numbers . get ( docID ) . longValue ( ) ) ) , DEFAULT . getInts ( ar , "number" , false ) . get ( docID ) ) ; break ; case 3 : assertEquals ( numbers . get ( docID ) . longValue ( ) , DEFAULT . getLongs ( ar , "number" , false ) . get ( docID ) ) ; break ; case 4 : assertEquals ( Float . intBitsToFloat ( ( ( int ) ( numbers . get ( docID ) . longValue ( ) ) ) ) , DEFAULT . getFloats ( ar , "number" , false ) . get ( docID ) , 0.0F ) ; break ; case 5 : assertEquals ( Double . longBitsToDouble ( numbers . get ( docID ) . longValue ( ) ) , DEFAULT . getDoubles ( ar , "number" , false ) . get ( docID ) , 0.0 ) ; break ; } bdv . get ( docID , scratch ) ; assertEquals ( binary . get ( docID ) , scratch ) ; sdv . get ( docID , scratch2 ) ; assertEquals ( sorted . get ( docID ) , scratch2 ) ; } } catch ( Exception e ) { throw new RuntimeException ( e ) ; } } } ; thread . start ( ) ; threads . add ( thread ) ; } startingGun . countDown ( ) ; for ( Thread thread : threads ) { thread . join ( ) ; } r . close ( ) ; dir . close ( ) ; } public void test2 ( ) throws Exception { } }

Fix:
BinaryDocValues bdv = DEFAULT . getTerms ( ar , "bytes" , false ) ;