Skip to content

Commit

Permalink
optimize code for better performance
Browse files Browse the repository at this point in the history
  • Loading branch information
SilenceDut committed May 13, 2019
1 parent 7caf8c4 commit 2af299a
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 108 deletions.
3 changes: 0 additions & 3 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions app/src/main/java/com/silencedut/hubdemo/ITestApi1Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,9 @@ public void test(Context context) {
@Override
public void onCreate() {

try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}

Log.d("ImplHub","ITestApi1Impl onCreate");
// ITestApi mApi1 = Hub.getImpl(ITestApi.class);
ITestApi mApi1 = Hub.getImpl(ITestApi.class);
Log.d("ImplHub","ITestApi1Impl onCreate after");
// Toast.makeText(App.getInsatnce(),"ITestApi1Impl 的 onCreate",Toast.LENGTH_LONG).show();
// Hub.getImpl(ITestApi.class).test(App.getInsatnce());
Expand Down
28 changes: 14 additions & 14 deletions app/src/main/java/com/silencedut/hubdemo/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,25 @@ public void run() {
} catch (InterruptedException e) {
e.printStackTrace();
}
Hub.getImpl(ITestApi1.class);
Hub.getImpl(ITestApi.class);
Log.d(TAG,"mThread2");
}
});
mThread2.start();

new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(12);
} catch (InterruptedException e) {
e.printStackTrace();
}
Hub.getImpl(ITestApi.class);
Hub.getImpl(ITestApi1.class);
Log.d(TAG,"mThread3");
}
}).start();
// new Thread(new Runnable() {
// @Override
// public void run() {
// try {
// Thread.sleep(12);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// Hub.getImpl(ITestApi.class);
// Hub.getImpl(ITestApi1.class);
// Log.d(TAG,"mThread3");
// }
// }).start();

}else {
Log.d("ImplHub", Arrays.toString(mThread1.getStackTrace()));
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/com/silencedut/hubdemo/TestImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ public void onCreate() {
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("ImplHub","ImplHub onCreate");
Hub.getImpl(ITestApi1.class);
Log.d("ImplHub","ImplHub onCreate after");
Log.d("ImplHub","TestImpl onCreate");
Log.d("ImplHub","TestImpl onCreate after");
}

@Override
Expand Down
183 changes: 101 additions & 82 deletions hub/src/main/java/com/silencedut/hub/navigation/impl/ImplHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@
import com.silencedut.hub_annotation.IFindImplClz;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Collector;

/**
* @author SilenceDut
* @date 2018/8/9
*/
public class ImplHub {

private enum HubMonitor {
/**
* hub class对象公用锁,避免直接锁class可能造成的死锁。length 必须为 2的n次方,用位运算代替求余数
Expand All @@ -31,17 +34,17 @@ private enum HubMonitor {
private static final String IMPL_HELPER_SUFFIX = "ImplHelper";

/**
try park 100ms
* try park 100ms
*/
private static final long THREAD_PARK_NANOS = 50*1000000;

private static final long THREAD_PARK_NANOS = 50 * 1000000;

private static final int INIT_STATE = -1;
private static final int CREATED = -2;

private static Map<Class, IHub> sRealImpls = new ConcurrentHashMap<>();
private static Map<Class<? extends IHub>, IHub> sRealImpls = new ConcurrentHashMap<>();
private static Map<Class, AtomicLong> sImplCtls = new ConcurrentHashMap<>();
private static Map<Thread,Long> sThreadWaiter = new ConcurrentHashMap<>();
private static Map<Thread, Long> sThreadWaiter = new ConcurrentHashMap<>();

/**
* 一个接口只能对应一个实现,之前的实现会被替换掉
*
Expand All @@ -58,113 +61,128 @@ private static void putImpl(Class api, IHub impl) {
public static <T extends IHub> T getImpl(Class<T> iHub) {

if (!iHub.isInterface()) {
Hub.sHubConfig.getIHubLog().error(TAG, String.format("interfaceType must be a interface , %s is not a interface",
iHub.getName()), new IllegalArgumentException("interfaceType must be a interface"));
Hub.sHubConfig.getIHubLog()
.error(TAG, String.format("interfaceType must be a interface , %s is not a interface",
iHub.getName()), new IllegalArgumentException("interfaceType must be a interface"));
}

AtomicLong ctl = getCtls(iHub);

IHub realImpl = sRealImpls.get(iHub);

if (realImpl == null) {
while (sRealImpls.get(iHub) == null) {
AtomicLong ctl = getCtls(iHub);
long currentThreadId = Thread.currentThread().getId();
while (ctl.get() != CREATED) {
if (ctl.compareAndSet(INIT_STATE, currentThreadId)) {
Hub.sHubConfig.getIHubLog().info(TAG,
iHub+" onCreate before "+",Thread:"+Thread.currentThread());
IFindImplClz iFindImplClzHelper ;
try {
iFindImplClzHelper = findImplHelper(iHub);
} catch (Exception e) {
ctl.compareAndSet(currentThreadId, INIT_STATE);
Hub.sHubConfig.getIHubLog().error(TAG,
iHub+" findImplHelper error "+",Thread:"+Thread.currentThread(),e);
return (T) new ImplHandler(iHub).mImplProxy;
}

realImpl = (IHub) iFindImplClzHelper.getInstance();



realImpl.onCreate();
for (Class apiClass : iFindImplClzHelper.getApis()) {
putImpl(apiClass, realImpl);
}
ctl.set(CREATED);
releaseWaiter(iHub);
Hub.sHubConfig.getIHubLog().info(TAG,
iHub+" onCreate after "+" ,Thread:"+Thread.currentThread());
} else if (ctl.get() == currentThreadId) {
Hub.sHubConfig.errorUseHandler.errorUseHub(
"getImpl api:"+iHub+ " error,recursion onCreate() on same thread,check api impl " +
"init 、 constructor 、onCreate() to avoid circular reference,",
ErrorUseHandleException.traceToString(2, Thread.currentThread().getStackTrace()));
break;
} else if (ctl.get() != CREATED) {
if(checkDeadLock(iHub,ctl.get())) {
break;
} else {
addAndParkWaiter(iHub,ctl);
}
if (ctl.compareAndSet(INIT_STATE, currentThreadId)) {
Hub.sHubConfig.getIHubLog().info(TAG,
iHub + " onCreate before " + ",Thread:" + Thread.currentThread());
IFindImplClz iFindImplClzHelper;
try {
iFindImplClzHelper = findImplHelper(iHub);
} catch (Exception e) {
ctl.compareAndSet(currentThreadId, INIT_STATE);
Hub.sHubConfig.getIHubLog().error(TAG,
iHub + " findImplHelper error " + ",Thread:" + Thread.currentThread(), e);
return exceptionHandler(iHub);
}

if(Thread.currentThread().isInterrupted()) {
if (ctl.get() != CREATED && ctl.compareAndSet(currentThreadId, INIT_STATE)){
Hub.sHubConfig.getIHubLog().info(TAG,
iHub+" thread interrupted ,return proxy for the moment"+",Thread:"+Thread.currentThread());
return (T) new ImplHandler(iHub).mImplProxy;
}
IHub realImpl = (IHub) iFindImplClzHelper.getInstance();

realImpl.onCreate();
for (Class apiClass : iFindImplClzHelper.getApis()) {
putImpl(apiClass, realImpl);
}
ctl.set(CREATED);

releaseWaiter(iHub);
Hub.sHubConfig.getIHubLog().info(TAG,
iHub + " onCreate after " + " ,Thread:" + Thread.currentThread());
} else if (ctl.get() == currentThreadId) {
Hub.sHubConfig.errorUseHandler.errorUseHub(
"getImpl api:" + iHub + " error,recursion onCreate() on same thread,check api impl " +
"init 、 constructor 、onCreate() to avoid circular reference,",
ErrorUseHandleException.traceToString(2, Thread.currentThread().getStackTrace()));
break;
} else if (ctl.get() != CREATED) {
if (checkDeadLock(iHub, ctl.get())) {
return exceptionHandler(iHub);
} else {
addAndParkWaiter(iHub, ctl);
}
}

if (Thread.currentThread().isInterrupted()) {
Hub.sHubConfig.getIHubLog().info(TAG,
iHub + " thread interrupted ,return proxy for the moment" + ",Thread:" +
Thread.currentThread());
return exceptionHandler(iHub);
}
}
return (T) sRealImpls.get(iHub);
}


private static <T extends IHub> T exceptionHandler(Class<T> iHub) {
if (sRealImpls.get(iHub) == null) {

return (T) new ImplHandler(iHub).mImplProxy;
} else {
return (T) sRealImpls.get(iHub);
}
}

/**
* 检查是否存在不同线程里onCreate循环调用的问题.根据策略让一个线程退出或者让App抛出崩溃,破怀# 等待不释放的条件 #避免类似死锁
* @param iHub 当前线程尝试获取的接口
*
* @param iHub 当前线程尝试获取的接口
* @param currentWaitFor 当前线程等待currentWaitFor线程的初始化
* @return 是否形成不同线程间的循环初始化
*/
private static boolean checkDeadLock(Class iHub,long currentWaitFor) {
synchronized (monitor(iHub)) {
Thread current = Thread.currentThread();
for(Map.Entry<Thread,Long> waitForPair : sThreadWaiter.entrySet()) {
if(waitForPair.getValue() == current.getId()) {
if(waitForPair.getKey().getId() == currentWaitFor) {
Hub.sHubConfig.getIHubLog().info(TAG, current +" leave "+currentWaitFor+ ","+iHub);
//一般是在不同线程初始化互相引用导致
Hub.sHubConfig.errorUseHandler.errorUseHub(
"getImpl api:"+iHub+ " error,recursion on multi thread,check api impl " +
"init 、 constructor 、onCreate() to avoid circular reference"
, ErrorUseHandleException.traceToString(2, Thread.currentThread().getStackTrace()));
return true;
}
}
}

private static boolean checkDeadLock(Class iHub, long currentWaitFor) {

Map<Long, Long> checkDeadMap = new HashMap<>(8);
for (Map.Entry<Thread, Long> threadWait : sThreadWaiter.entrySet()) {
checkDeadMap.put(threadWait.getKey().getId(), threadWait.getValue());
}
Long current = Thread.currentThread().getId();
Long temp = checkDeadMap.get(current);
while (temp != null && !temp.equals(current)) {
temp = checkDeadMap.get(temp);
}
boolean deadLock = temp!=null;
if(deadLock) {
Hub.sHubConfig.getIHubLog().info(TAG, current + " leave " + currentWaitFor + "," + iHub);
//一般是在不同线程初始化互相引用导致
Hub.sHubConfig.errorUseHandler.errorUseHub(
"getImpl api:" + iHub + " error,recursion on multi thread,check api impl " +
"init 、 constructor 、onCreate() to avoid circular reference"
, ErrorUseHandleException.traceToString(2, Thread.currentThread().getStackTrace()));
}
return false;
return deadLock;
}

/**
* 如果其他线程在执行iHub的onCreate方法,等待执行完,通过LockSupport.parkNanos避免cpu的无谓消耗和一些未考虑的情况下导致的无法中止的park
* @param iHub 想要获取的接口
*
* @param iHub 想要获取的接口
* @param currentWaitFor 当前真正初始化该接口的对象id
*/
private static void addAndParkWaiter(Class iHub,AtomicLong currentWaitFor) {
private static void addAndParkWaiter(Class iHub, AtomicLong currentWaitFor) {
Thread current = Thread.currentThread();
if(sThreadWaiter.get(current) == null && currentWaitFor.get() != CREATED) {
sThreadWaiter.put(current,currentWaitFor.get());
if (sThreadWaiter.get(current) == null && currentWaitFor.get() != CREATED) {
sThreadWaiter.put(current, currentWaitFor.get());
Hub.sHubConfig.getIHubLog().info(TAG,
"park thread :"+current +",waiting for threadId on "+currentWaitFor + " to create impl of "+iHub);
LockSupport.parkNanos(iHub,THREAD_PARK_NANOS);
"park thread :" + current + ",waiting for threadId on " + currentWaitFor + " to create impl of " +
iHub);
LockSupport.parkNanos(iHub, THREAD_PARK_NANOS);
}
}

private static void releaseWaiter(Class iHub) {
private static void releaseWaiter(Class iHub) {
Hub.sHubConfig.getIHubLog().info(TAG, "releaseWaiter :" + iHub);
Thread current = Thread.currentThread();
for (Map.Entry<Thread, Long> lockPair : sThreadWaiter.entrySet()) {

if (lockPair.getValue() == current.getId()) {
Hub.sHubConfig.getIHubLog().info(TAG,
"releaseWaiter :" + lockPair+",block:"+ LockSupport.getBlocker(lockPair.getKey()));
if (LockSupport.getBlocker(lockPair.getKey()) == iHub) {
Hub.sHubConfig.getIHubLog().info(TAG, "unPark thread :" + lockPair.getKey());
LockSupport.unpark(lockPair.getKey());
Expand Down Expand Up @@ -200,7 +218,8 @@ private static IFindImplClz findImplHelper(Class iHub) throws Exception {

String apiName = apiCanonicalName.substring(apiCanonicalName.lastIndexOf(Hub.PACKAGER_SEPARATOR) + 1);

String implCanonicalName = packageName + Hub.PACKAGER_SEPARATOR + apiName + Hub.CLASS_NAME_SEPARATOR + IMPL_HELPER_SUFFIX;
String implCanonicalName =
packageName + Hub.PACKAGER_SEPARATOR + apiName + Hub.CLASS_NAME_SEPARATOR + IMPL_HELPER_SUFFIX;
return (IFindImplClz) Class.forName(implCanonicalName).newInstance();
}

Expand Down

0 comments on commit 2af299a

Please sign in to comment.