先學會JAVA,至少你看單個方法的時候,能看懂這個方法是做什麼的。弄個myeclipse之類的軟體,將代碼運行一遍,看看是幹嘛的。然後先瀏覽一下主函數,裡面的具體的類可以先不管,先把主函數從頭到尾仔細看看,應該大概能知道這程序是幹嘛的了。接著就設斷點,按F6一步一步看。從頭細讀,遇到什麼類就先進去掃一下,稍微了解一下結構就行。然後具體看調用的方法,調哪個就看哪個,最好看懂方法的具體實現。如果一下子實在看不懂,那就自己在後面加個注釋方便呆會回來繼續看。先看後面的,這一行一行讀,不要怕麻煩,剛剛開始是慢點,讀得多了就基本能一掃而過了。
B. 北大青鳥java培訓:提高代碼閱讀能力的技巧有哪些
對於學習軟體開發的人來說,學會閱讀源代碼是非常重要的,然而很多人並不具備閱讀源代碼的能力。
很多人不喜歡閱讀源代碼,認為這是非常無聊的事情。
如果不會閱讀源代碼備擾,對於後面寫代碼是非常困難的,很多開發人員主要把重心放在寫代碼上,反而忽略代碼的閱讀。
閱讀代碼是非常關鍵的,下面天津電腦培訓為大家介紹閱讀代碼的技巧。
1、學會運行代碼運行代碼是閱讀代碼的第一步,這樣能夠了解關於項目的很多細節,並且了解怎麼進行運行,掌握庫的使用方法。
這樣是了解一個項目最好的方法,如果能夠自己了解和編寫相關的項目,這樣對於使用框架和庫會有自己的想法。
2、找到高層次的邏輯當您開始閱讀項目的代碼時,會涉及到每個細節。
相反的,你還需要掌握高層次結構,從這個地方找到入口點,在很多大型項目開發中都可以使用這種方法。
如果是進行web程序開發,那麼天津IT培訓建議應該查看不同的包,例如存儲業務邏輯的位置,存儲UI代碼的位置,控制器所在的位手滾悄置等等。
3、了解和使用工具很多工具都可以有助於源代碼閱讀,並且對可視化代碼有很大的幫助。
在使用過程中,天津IT培訓認為IntelliJIdea工具能夠導航源代碼,允許使用單詞的一部分,甚至單詞的縮寫進行搜索。
您還應該學習鍵盤的快捷鍵。
使用滑鼠導航源代碼可能會非常無聊和緩慢,鍵盤快捷鍵可以更快的進行跳轉。
4、了解語言更深入地了解特定語畢渣言有助於提高您的代碼閱讀技能。
每種語言都有自己的約定,樣式和語法。
這些知識可以幫助您快速熟悉特定代碼。
其中天津電腦培訓發現在Java語言中,方法名稱以小寫字母開頭,而在C#語言中,方法名稱以大寫字母開頭。
了解這種差異可以幫助你從源代碼中找到識別方法。
C. 如何看java源代碼
在eclipse中查看源文件用 「Ctrl+超找的源文件」 就可以了。 如我要查看String 我按住Ctrl,然後用滑鼠移動到String下面點擊就行了。
如果彈出一個窗口, 說「Source not found ... ... 」
在彈出的窗口上點擊那個按鈕「attach source」,會出來一個窗口讓你選擇jdk源碼包所在的位置,你選擇一下,比如在我機器上是「C:\Program Files\Java\jdk1.6.0_03\src.zip」,你類比著找一下,這樣就可以用「Ctrl+超找的類名「了。
D. 學習JAVA的同學都是怎麼讀源碼的
E. 一開始學習java有必要看源代碼嗎諸如Arraylist,Linkedlist的這些源代碼
你好,看源碼是可以幫助你以後寫代碼的。如果你是剛開始學,就沒有必要看那些東西。但是你要是有能力的話,看看還是很有幫助的,你說的那幾個類,等你學習到了,最好還是看看,可以加深你對他們的理解。
F. 怎樣高效的閱讀JavaWeb項目源代碼
首先要理清楚代碼結構和業務結構(應該有些文檔或者大的流程圖),這是閱讀具體代碼的前提。
閱讀Javaweb項目的代碼:
你需要找到
View層的代碼:前端頁面、圖片、資源文件都在其中。
Controller層的代碼:控制試圖與模型層以及數據傳遞。
Service層的代碼:業務邏輯。
Dao層的代碼:資料庫訪問邏輯。
從web.xml-appcontext.xml-xxx
G. 二次開發怎麼閱讀別人的java源碼
剛剛開始工作的人往往會自認為不好意思打擾同事,其實這是一個誤解,完全是自己的心理因素在作怪。這種時間你就應當去打擾他們,問問是如何去測試。相信一個項目經理在招聘你的時候,絕對不可能是將你當作一個完全的熟手去看待的,你問同事們,同事們肯定的會幫你,並且不會恥笑你的不懂。任何問題,如果自己瞎琢磨超過了15分鍾,就別再去想了,趕緊問熟悉的人吧。
H. 如何快速讀懂項目源碼javaWeb
一:學會如何讀一個JavaWeb項目源代碼 步驟:表結構->web.xml->mvc->db->spring
ioc->log-> 代碼
1、先了解項目資料庫的表結構,這個方面是最容易忘記 的,有時候我們只顧著看每一個方法是怎麼進行的,卻沒
有去了解資料庫之間的主外鍵關聯。其實如果先了解數據 庫表結構,再去看一個方法的實現會更加容易。
2、然後需要過一遍web.xml,知道項目中用到了什麼攔
截器,監聽器,過濾器,擁有哪些配置文件。如果是攔截 器,一般負責過濾請求,進行AOP 等;如果是監 可能是定時任務,初始化任務;配置文件有如使用了 spring
後的讀取mvc 相關,db 相關,service 相關,aop 相關的文件。
3、查看攔截器,監聽器代碼,知道攔截了什麼請求,這
個類完成了怎樣的工作。有的人就是因為缺少了這一步, 自己寫了一個action,配置文件也沒有寫錯,但是卻怎麼
調試也無法進入這個action,直到別人告訴他,請求被攔
4、接下來,看配置文件,首先一定是mvc相關的,如 springmvc
中,要請求哪些請求是靜態資源,使用了哪些 view 策略,controller 註解放在哪個包下等。 然後是db 相關配置文件,看使用了什麼資料庫,使用了
什麼orm框架,是否開啟了二級緩存,使用哪種產品作 為二級緩存,事務管理的處理,需要掃描的實體類放在什 么位置。最後是spring 核心的ioc
功能相關的配置文件, 知道介面與具體類的注入大致是怎樣的。當然還有一些如 apectj 置文件,也是在這個步驟中完成
5、log
相關文件,日誌的各個級別是如何處理的,在哪些 地方使用了log 記錄日誌
6、從上面幾點後知道了整個開源項目的整體框架,閱讀 每個方法就不再那麼難了。
7、當然如果有項目配套的開發文檔也是要閱讀的。
I. java並發包源碼怎麼讀
1. 各種同步控制工具的使用
1.1 ReentrantLock
ReentrantLock感覺上是synchronized的增強版,synchronized的特點是使用簡單,一切交給JVM去處理,但是功能上是比較薄弱的。在JDK1.5之前,ReentrantLock的性能要好於synchronized,由於對JVM進行了優化,現在的JDK版本中,兩者性能是不相上下的。如果是簡單的實現,不要刻意去使用ReentrantLock。
相比於synchronized,ReentrantLock在功能上更加豐富,它具有可重入、可中斷、可限時、公平鎖等特點。
首先我們通過一個例子來說明ReentrantLock最初步的用法:
package test;
import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock = new ReentrantLock(); public static int i = 0;
@Override public void run() { for (int j = 0; j < 10000000; j++)
{ lock.lock(); try
{
i++;
} finally
{ lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
有兩個線程都對i進行++操作,為了保證線程安全,使用了ReentrantLock,從用法上可以看出,與synchronized相比,ReentrantLock就稍微復雜一點。因為必須在finally中進行解鎖操作,如果不在finally解鎖,有可能代碼出現異常鎖沒被釋放,而synchronized是由JVM來釋放鎖。
那麼ReentrantLock到底有哪些優秀的特點呢?
1.1.1 可重入
單線程可以重復進入,但要重復退出
lock.lock();
lock.lock();try{
i++;
}
finally{
lock.unlock();
lock.unlock();
}
由於ReentrantLock是重入鎖,所以可以反復得到相同的一把鎖,它有一個與鎖相關的獲取計數器,如果擁有鎖的某個線程再次得到鎖,那麼獲取計數器就加1,然後鎖需要被釋放兩次才能獲得真正釋放(重入鎖)。這模仿了synchronized的語義;如果線程進入由線程已經擁有的監控器保護的 synchronized 塊,就允許線程繼續進行,當線程退出第二個(或者後續)synchronized塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個synchronized塊時,才釋放鎖。
public class Child extends Father implements Runnable{ final static Child child = new Child();//為了保證鎖唯一
public static void main(String[] args) { for (int i = 0; i < 50; i++) { new Thread(child).start();
}
}
public synchronized void doSomething() {
System.out.println("1child.doSomething()");
doAnotherThing(); // 調用自己類中其他的synchronized方法
}
private synchronized void doAnotherThing() { super.doSomething(); // 調用父類的synchronized方法
System.out.println("3child.doAnotherThing()");
}
@Override
public void run() {
child.doSomething();
}
}class Father { public synchronized void doSomething() {
System.out.println("2father.doSomething()");
}
}
我們可以看到一個線程進入不同的synchronized方法,是不會釋放之前得到的鎖的。所以輸出還是順序輸出。所以synchronized也是重入鎖
輸出:
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
...
1.1.2.可中斷
與synchronized不同的是,ReentrantLock對中斷是有響應的。中斷相關知識查看[高並發Java 二] 多線程基礎
普通的lock.lock()是不能響應中斷的,lock.lockInterruptibly()能夠響應中斷。
我們模擬出一個死鎖現場,然後用中斷來處理死鎖
package test;import java.lang.management.ManagementFactory;import java.lang.management.ThreadInfo;import java.lang.management.ThreadMXBean;import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock1 = new ReentrantLock(); public static ReentrantLock lock2 = new ReentrantLock(); int lock; public Test(int lock)
{ this.lock = lock;
} @Override
public void run()
{ try
{ if (lock == 1)
{
lock1.lockInterruptibly(); try
{
Thread.sleep(500);
} catch (Exception e)
{ // TODO: handle exception
}
lock2.lockInterruptibly();
} else
{
lock2.lockInterruptibly(); try
{
Thread.sleep(500);
} catch (Exception e)
{ // TODO: handle exception
}
lock1.lockInterruptibly();
}
} catch (Exception e)
{ // TODO: handle exception
} finally
{ if (lock1.isHeldByCurrentThread())
{
lock1.unlock();
} if (lock2.isHeldByCurrentThread())
{
lock2.unlock();
}
System.out.println(Thread.currentThread().getId() + ":線程退出");
}
} public static void main(String[] args) throws InterruptedException {
Test t1 = new Test(1);
Test t2 = new Test(2);
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
Thread.sleep(1000); //DeadlockChecker.check();
} static class DeadlockChecker
{ private final static ThreadMXBean mbean = ManagementFactory
.getThreadMXBean(); final static Runnable deadlockChecker = new Runnable()
{ @Override
public void run()
{ // TODO Auto-generated method stub
while (true)
{ long[] deadlockedThreadIds = mbean.findDeadlockedThreads(); if (deadlockedThreadIds != null)
{
ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds); for (Thread t : Thread.getAllStackTraces().keySet())
{ for (int i = 0; i < threadInfos.length; i++)
{ if(t.getId() == threadInfos[i].getThreadId())
{
t.interrupt();
}
}
}
} try
{
Thread.sleep(5000);
} catch (Exception e)
{ // TODO: handle exception
}
}
}
};
public static void check()
{
Thread t = new Thread(deadlockChecker);
t.setDaemon(true);
t.start();
}
}
}
上述代碼有可能會發生死鎖,線程1得到lock1,線程2得到lock2,然後彼此又想獲得對方的鎖。
我們用jstack查看運行上述代碼後的情況
下面舉個例子:
package test;import java.util.concurrent.CyclicBarrier;public class Test implements Runnable{ private String soldier; private final CyclicBarrier cyclic; public Test(String soldier, CyclicBarrier cyclic)
{ this.soldier = soldier; this.cyclic = cyclic;
} @Override
public void run()
{ try
{ //等待所有士兵到齊
cyclic.await();
dowork(); //等待所有士兵完成工作
cyclic.await();
} catch (Exception e)
{ // TODO Auto-generated catch block
e.printStackTrace();
}
} private void dowork()
{ // TODO Auto-generated method stub
try
{
Thread.sleep(3000);
} catch (Exception e)
{ // TODO: handle exception
}
System.out.println(soldier + ": done");
} public static class BarrierRun implements Runnable
{ boolean flag; int n; public BarrierRun(boolean flag, int n)
{ super(); this.flag = flag; this.n = n;
} @Override
public void run()
{ if (flag)
{
System.out.println(n + "個任務完成");
} else
{
System.out.println(n + "個集合完成");
flag = true;
}
}
} public static void main(String[] args)
{ final int n = 10;
Thread[] threads = new Thread[n]; boolean flag = false;
CyclicBarrier barrier = new CyclicBarrier(n, new BarrierRun(flag, n));
System.out.println("集合"); for (int i = 0; i < n; i++)
{
System.out.println(i + "報道");
threads[i] = new Thread(new Test("士兵" + i, barrier));
threads[i].start();
}
}
}
列印結果:
集合
士兵5: done士兵7: done士兵8: done士兵3: done士兵4: done士兵1: done士兵6: done士兵2: done士兵0: done士兵9: done10個任務完成
1.7 LockSupport
提供線程阻塞原語
和suspend類似
LockSupport.park();
LockSupport.unpark(t1);
與suspend相比不容易引起線程凍結
LockSupport的思想呢,和Semaphore有點相似,內部有一個許可,park的時候拿掉這個許可,unpark的時候申請這個許可。所以如果unpark在park之前,是不會發生線程凍結的。
下面的代碼是[高並發Java 二] 多線程基礎中suspend示例代碼,在使用suspend時會發生死鎖。
而使用LockSupport則不會發生死鎖。
另外
park()能夠響應中斷,但不拋出異常。中斷響應的結果是,park()函數的返回,可以從Thread.interrupted()得到中斷標志。
在JDK當中有大量地方使用到了park,當然LockSupport的實現也是使用unsafe.park()來實現的。
public static void park() { unsafe.park(false, 0L);
}
1.8 ReentrantLock 的實現
下面來介紹下ReentrantLock的實現,ReentrantLock的實現主要由3部分組成:
CAS狀態
等待隊列
park()
ReentrantLock的父類中會有一個state變數來表示同步的狀態
通過CAS操作來設置state來獲取鎖,如果設置成了1,則將鎖的持有者給當前線程
如果拿鎖不成功,則會做一個申請
首先,再去申請下試試看tryAcquire,因為此時可能另一個線程已經釋放了鎖。
如果還是沒有申請到鎖,就addWaiter,意思是把自己加到等待隊列中去
其間還會有多次嘗試去申請鎖,如果還是申請不到,就會被掛起
同理,如果在unlock操作中,就是釋放了鎖,然後unpark,這里就不具體講了。
2. 並發容器及典型源碼分析
2.1ConcurrentHashMap
我們知道HashMap不是一個線程安全的容器,最簡單的方式使HashMap變成線程安全就是使用Collections.synchronizedMap,它是對HashMap的一個包裝
同理對於List,Set也提供了相似方法。
但是這種方式只適合於並發量比較小的情況。
我們來看下synchronizedMap的實現
它會將HashMap包裝在裡面,然後將HashMap的每個操作都加上synchronized。
由於每個方法都是獲取同一把鎖(mutex),這就意味著,put和remove等操作是互斥的,大大減少了並發量。
下面來看下ConcurrentHashMap是如何實現的
在ConcurrentHashMap內部有一個Segment段,它將大的HashMap切分成若干個段(小的HashMap),然後讓數據在每一段上Hash,這樣多個線程在不同段上的Hash操作一定是線程安全的,所以只需要同步同一個段上的線程就可以了,這樣實現了鎖的分離,大大增加了並發量。
在使用ConcurrentHashMap.size時會比較麻煩,因為它要統計每個段的數據和,在這個時候,要把每一個段都加上鎖,然後再做數據統計。這個就是把鎖分離後的小小弊端,但是size方法應該是不會被高頻率調用的方法。
在實現上,不使用synchronized和lock.lock而是盡量使用trylock,同時在HashMap的實現上,也做了一點優化。這里就不提了。
2.2BlockingQueue
BlockingQueue不是一個高性能的容器。但是它是一個非常好的共享數據的容器。是典型的生產者和消費者的實現。