private WorkUnit<Material,W> enqueueWork( W work ) { WorkUnit<Material,W> unit = new WorkUnit<>( work, Thread.currentThread() ); unit.next = stack.getAndSet( unit ); // benign race, see the batch.next read-loop in combine() return unit; }
void park( long time, TimeUnit unit ) { if ( compareAndSet( STATE_QUEUED, STATE_PARKED ) ) { LockSupport.parkNanos( unit.toNanos( time ) ); compareAndSet( STATE_PARKED, STATE_QUEUED ); } }
private boolean tryLock( int tryCount, WorkUnit<Material,W> unit, boolean block ) { if ( lock.compareAndSet( null, Thread.currentThread() ) ) { // Got the lock! return true; } // Did not get the lock, spend some time until our work has either been completed, // or we get the lock. if ( tryCount < 10 ) { // todo Java9: Thread.onSpinWait() ? Thread.yield(); } else if ( block ) { unit.park( 10, TimeUnit.MILLISECONDS ); } return false; }
/** * Apply the given work to the material in a thread-safe way, possibly by * combining it with other work. * * @param work The work to be done. * @throws ExecutionException if this thread ends up performing the piled up work, * and any work unit in the pile throws an exception. Thus the current thread is not * guaranteed to observe any exception its unit of work might throw, since the * exception will be thrown in whichever thread that ends up actually performing the work. */ public void apply( W work ) throws ExecutionException { // Schedule our work on the stack. WorkUnit<Material,W> unit = enqueueWork( work ); // Try grabbing the lock to do all the work, until our work unit // has been completed. int tryCount = 0; do { tryCount++; checkFailure( tryDoWork( unit, tryCount, true ) ); } while ( !unit.isDone() ); }
private boolean tryLock( int tryCount, WorkUnit<Material,W> unit, boolean block ) { if ( lock.compareAndSet( null, Thread.currentThread() ) ) { // Got the lock! return true; } // Did not get the lock, spend some time until our work has either been completed, // or we get the lock. if ( tryCount < 10 ) { // todo Java9: Thread.onSpinWait() ? Thread.yield(); } else if ( block ) { unit.park( 10, TimeUnit.MILLISECONDS ); } return false; }
boolean isDone() { return get() == STATE_DONE; }
void park( long time, TimeUnit unit ) { if ( compareAndSet( STATE_QUEUED, STATE_PARKED ) ) { LockSupport.parkNanos( unit.toNanos( time ) ); compareAndSet( STATE_PARKED, STATE_QUEUED ); } }
@Override public void await() throws ExecutionException { checkFailure( throwable ); int tryCount = 0; while ( !unit.isDone() ) { tryCount++; checkFailure( throwable = tryDoWork( unit, tryCount, true ) ); } } };
private void markAsDone( WorkUnit<Material,W> batch ) { while ( batch != stackEnd ) { batch.complete(); batch = batch.next; } }
private void unparkAnyWaiters() { WorkUnit<Material,W> waiter = stack.get(); if ( waiter != stackEnd ) { waiter.unpark(); } }
private WorkUnit<Material,W> enqueueWork( W work ) { WorkUnit<Material,W> unit = new WorkUnit<>( work, Thread.currentThread() ); unit.next = stack.getAndSet( unit ); // benign race, see the batch.next read-loop in combine() return unit; }
/** * Apply the given work to the material in a thread-safe way, possibly by * combining it with other work. * * @param work The work to be done. * @throws ExecutionException if this thread ends up performing the piled up work, * and any work unit in the pile throws an exception. Thus the current thread is not * guaranteed to observe any exception its unit of work might throw, since the * exception will be thrown in whichever thread that ends up actually performing the work. */ public void apply( W work ) throws ExecutionException { // Schedule our work on the stack. WorkUnit<Material,W> unit = enqueueWork( work ); // Try grabbing the lock to do all the work, until our work unit // has been completed. int tryCount = 0; do { tryCount++; checkFailure( tryDoWork( unit, tryCount, true ) ); } while ( !unit.isDone() ); }
boolean isDone() { return get() == STATE_DONE; }
@Override public void await() throws ExecutionException { checkFailure( throwable ); int tryCount = 0; while ( !unit.isDone() ) { tryCount++; checkFailure( throwable = tryDoWork( unit, tryCount, true ) ); } } };
private void unparkAnyWaiters() { WorkUnit<Material,W> waiter = stack.get(); if ( waiter != stackEnd ) { waiter.unpark(); } }
private void markAsDone( WorkUnit<Material,W> batch ) { while ( batch != stackEnd ) { batch.complete(); batch = batch.next; } }