Skip to content

Instantly share code, notes, and snippets.

@cmaan
Last active July 20, 2017 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cmaan/7752e3c4fd0b1ba90a745cb6db232206 to your computer and use it in GitHub Desktop.
Save cmaan/7752e3c4fd0b1ba90a745cb6db232206 to your computer and use it in GitHub Desktop.
public class GrpcUtilPatchThreadFactories {
public static void patch() {
Resource<ExecutorService> SHARED_CHANNEL_EXECUTOR = new Resource<ExecutorService>() {
private static final String NAME = "grpc-default-executor";
@Override
public ExecutorService create() {
return Executors.newCachedThreadPool(getThreadFactory(NAME + "-%d", true));
}
@Override
public void close(ExecutorService instance) {
instance.shutdown();
}
@Override
public String toString() {
return NAME;
}
};
Resource<ScheduledExecutorService> TIMER_SERVICE = new Resource<ScheduledExecutorService>() {
@Override
public ScheduledExecutorService create() {
// We don't use newSingleThreadScheduledExecutor because it doesn't return a
// ScheduledThreadPoolExecutor.
ScheduledExecutorService service = Executors.newScheduledThreadPool(1,
getThreadFactory("grpc-timer-%d", true));
// If there are long timeouts that are cancelled, they will not actually be
// removed from
// the executors queue. This forces immediate removal upon cancellation to avoid
// a
// memory leak. Reflection is used because we cannot use methods added in Java
// 1.7. If
// the method does not exist, we give up. Note that the method is not present in
// 1.6, but
// _is_ present in the android standard library.
try {
Method method = service.getClass().getMethod("setRemoveOnCancelPolicy", boolean.class);
method.invoke(service, true);
} catch (NoSuchMethodException e) {
// no op
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
return service;
}
@Override
public void close(ScheduledExecutorService instance) {
instance.shutdown();
}
};
try {
Field f = GrpcUtil.class.getDeclaredField("SHARED_CHANNEL_EXECUTOR");
f.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.set(null, SHARED_CHANNEL_EXECUTOR);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw Throwables.propagate(e);
}
try {
Field f = GrpcUtil.class.getDeclaredField("TIMER_SERVICE");
f.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.set(null, TIMER_SERVICE);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw Throwables.propagate(e);
}
}
private static ThreadFactory getThreadFactory(String nameFormat, boolean daemon) {
return new ThreadFactoryBuilder().setThreadFactory(Executors.defaultThreadFactory()).setDaemon(daemon)
.setNameFormat(nameFormat).build();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment