Last active
July 20, 2017 16:35
-
-
Save cmaan/7752e3c4fd0b1ba90a745cb6db232206 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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