背景
年初開發(fā)了一個項目河胎,項目中有這樣一個需求,需要每隔一秒鐘向服務(wù)器發(fā)起一次狀態(tài)信息查詢指令虎敦,在這個過程中偶爾會主動發(fā)起一次狀態(tài)信息修改的指令(PS:因為服務(wù)器的處理能力有限游岳,必須間隔一秒才能發(fā)送命令,否則指令將不會被執(zhí)行)其徙。本來不是什么大問題胚迫,但是由于開發(fā)人員從事android開發(fā)時間較短,多線程用得也不多唾那,所以看似簡單的問題晌区,最后使得整個項目出現(xiàn)了較大的性能問題。下面主要講講如何一步步的優(yōu)化過程通贞。(本文適合初學(xué)者,大拍瘴澹可以繞道前行)昌罩。
優(yōu)化前
以下是功能部分代碼
public void sendOrderToServer(final byte[] data) {
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
order_queue.offer(data);//將指令放入隊列中
if (null != order_queue && order_queue.size() != 0) {
synchronized (lock) {
while (order_queue.size() != 0) {
try {
byte[] orderData = order_queue.poll();//取出隊首指令
int dataLength = orderData.length;
if (dataLength > 0) {
//發(fā)送指令到服務(wù)器
}
try {
Thread.sleep(1000);//等待一秒鐘,然后執(zhí)行下一條指令
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
});
thread.start();
}
代碼很簡單灾馒,相信大家都能看懂是什么意思茎用,閱讀下來好像也沒什么太大問題。模擬器運行一遍睬罗,沒有問題轨功,各項數(shù)據(jù)顯示正常。然后信心滿滿安裝到真機上容达,拍拍手古涧,歐??,搞定花盐∠刍可惜理想是美好的菇爪,現(xiàn)實是殘酷的,分分鐘啪啪啪打臉柒昏。app運行不到一分鐘凳宙,整個界面就開始卡頓了,操作屏幕毫無反應(yīng)职祷。這是為啥呢 氏涩??有梆?
然后認真閱讀了一下代碼是尖,發(fā)現(xiàn)里面用到了synchronized (lock)同步鎖,筆者為什么要這樣寫淳梦,估計是考慮到指令需要間隔一秒鐘才能發(fā)送析砸,又要保證指令是按序的。由于app每次發(fā)送命令都需要調(diào)用sendOrderToServer方法爆袍,并創(chuàng)建新的線程首繁。這就出現(xiàn)了一個問題,除了第一個線程能獲取到同步鎖陨囊,其他的線程都無法獲取到弦疮,因為order_queue隊列永遠不會為空。那么其他線程都相當于死鎖蜘醋,都無法執(zhí)行后面的代碼胁塞,也就不能釋放占用的系統(tǒng)資源。這樣線程不停的創(chuàng)建压语,系統(tǒng)資源被一點點消耗掉啸罢,最后造成界面卡頓。既然問題找到了胎食,那就好辦了扰才,其實優(yōu)化方法有很多,下面只是其中一種厕怜。
優(yōu)化后
public void sendOrderToServer(final byte[] data) {
order_queue.offer(data);
}
private class WriteThread extends Thread {
@Override
public void run() {
super.run();
while (true) {
if (null != order_queue && order_queue.size() != 0) {
byte[] orderData = order_queue.poll();
if (null != orderData) {
int dataLength = orderData.length;
if (dataLength > 0) {
//發(fā)送指令到服務(wù)器
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
只創(chuàng)建一個WriteThread對象衩匣,里面運行一個while (true)的循環(huán),發(fā)送指令時只需要調(diào)用sendOrderToServer方法粥航,往order_queue隊列中加入指令就好琅捏。
總結(jié)
1、項目中使用多線程加鎖時递雀,需要注意不要造成死鎖柄延。
2、如果需要創(chuàng)建大量的線程映之,請使用線程池來管理拦焚,減少線程創(chuàng)建的開銷蜡坊,以及資源的浪費。