第一篇:java培訓-Java高并發(大全)
Java高并發:靜態頁面生成方案
提升網站性能的方式有很多,例如有效的使用緩存,生成靜態頁面等等。今天要說的就是生成靜態頁面的方式。這個也是我近期一直在搞的一個問題,近期在做使用html + servlet做個人網站,為什么是這2個東西呢?
提升網站性能的方式有很多,例如有效的使用緩存,生成靜態頁面等等。今天要說的就是生成靜態頁面的方式。這個也是我近期一直在搞的一個問題,近期在做使用html + servlet做個人網站,為什么是這2個東西呢?
1、直接用servlet是為了保證網站能以最快的速度執行命令..個人總感覺像Struts hibernate spring之類的雖然方便但是效能帶來的損耗不太能接收
2、使用html同樣是為了保證最快的反應速度,畢竟html 比jsp少了一層服務器執行.速度上要快的多
一、在這里要先說一下什么是頁面靜態化:
簡單的說,我們如果訪問一個鏈接 http://abc.com/test.do,服務器對應的模塊會處理這個請求,轉到對應的jsp界面,最后生成我們想要看到的數據。這其中的缺點是顯而易見的:因為每次請求服務器都會進行處理,如果有太多的高并發請求,那么就會加重應用服務器的壓力,弄不好就把服務器 搞down 掉了。那么如何去避免呢?如果我們把對 test.do 請求后的結果保存成一個 html 文件,然后每次用戶都去訪問 http://abc.com/test.html,這樣應用服務器的壓力不就減少了?
那么靜態頁面從哪里來呢?總不能讓我們每個頁面都手動處理吧?這里就牽涉到我們要講解的內容了,靜態頁面生成方案...我們需要的是自動的生成靜態頁面,當用戶訪問 http://abc.com/test.do,會自動生成 test.html,然后顯示給用戶。
二、下面我們在簡單介紹一下要想掌握頁面靜態化方案應該掌握的知識點
1、基礎— URL Rewrite 什么是 URL Rewrite 呢 ? URL 重寫。用一個簡單的例子來說明問題:輸入網址http://www.tmdps.cn/test.do,但是實際上訪問的卻是 http://www.tmdps.cn/test.action,那我們就可以說 URL 被重寫了。這項技術應用廣泛,有許多開源的工具可以實現這個功能。
2、基礎— Servlet web.xml 如果你還不知道 web.xml 中一個請求和一個 servlet 是如何匹配到一起的,那么請搜索一下 servlet 的文檔。這可不是亂說呀,有很多人就認為 /xyz/*.do 這樣的匹配方式能有效。
如果你還不知道怎么編寫一個 servlet,那么請搜索一下如何編寫 servlet。這可不是說笑呀,在各種集成工具漫天飛舞的今天,很多人都不會去從零編寫一個 servlet了。
三、基本的方案介紹
其中,對于 URL Rewriter的部分,可以使用收費或者開源的工具來實現,如果 url不是特別的復雜,可以考慮在 servlet 中實現,那么就是下面這個樣子:
原文鏈接:中軟卓越http://www.tmdps.cn
第二篇:Java培訓
廣州傳智播客Java培訓的優勢在哪里?
眾所周知,傳智播客廣州Java培訓課程在業界可算是是一流的。計算機技術的發展日新月異,為緊跟技術潮流,廣州傳智播客多名資深Java專家,在多個預熱班的實踐基礎上,綜合課堂反饋,結合現今流行的多種實用技術,在原有課程再次加入了多個實用性、趣味性很強的Java項目:網絡螞蟻,網絡爬蟲,聊天系統。
傳智播客廣州Java培訓課程可謂是全國最牛的。由于受全球金融危機的影響,IT行業萎縮、人才需求下滑,現在的情況是:一個工作崗位往往幾佰人競爭,隊伍中更是不缺乏具有一、二年工作經驗的開發人員。如何讓自己在幾佰人的競爭中脫穎而出?沒有他途,只有把技術學的更深入,更牛,方能取勝。在廣州傳智播客學習Java課程不但可以讓你找到工作,更能讓你找到一份好工作。
心動不如行動,趕快來廣州傳智播客Java培訓機構學習吧!這里將會是你一個展示你技術價值的好平臺!
第三篇:關于Java并發編程的總結和思考
關于Java并發編程的總結和思考
編寫優質的并發代碼是一件難度極高的事情。Java語言從第一版本開始內置了對多線程的支持,這一點在當年是非常了不起的,但是當我們對并發編程有了更深刻的認識和更多的實踐后,實現并發編程就有了更多的方案和更好的選擇。本文是對并發編程的一點總結和思考,同時也分享了Java 5以后的版本中如何編寫并發代碼的一點點經驗。
為什么需要并發
并發其實是一種解耦合的策略,它幫助我們把做什么(目標)和什么時候做(時機)分開。這樣做可以明顯改進應用程序的吞吐量(獲得更多的CPU調度時間)和結構(程序有多個部分在協同工作)。做過Java Web開發的人都知道,Java Web中的Servlet程序在Servlet容器的支持下采用單實例多線程的工作模式,Servlet容器為你處理了并發問題。
誤解和正解
最常見的對并發編程的誤解有以下這些:
-并發總能改進性能(并發在CPU有很多空閑時間時能明顯改進程序的性能,但當線程數量較多的時候,線程間頻繁的調度切換反而會讓系統的性能下降)
-編寫并發程序無需修改原有的設計(目的與時機的解耦往往會對系統結構產生巨大的影響)
-在使用Web或EJB容器時不用關注并發問題(只有了解了容器在做什么,才能更好的使用容器)
下面的這些說法才是對并發客觀的認識:
-編寫并發程序會在代碼上增加額外的開銷
-正確的并發是非常復雜的,即使對于很簡單的問題
-并發中的缺陷因為不易重現也不容易被發現
-并發往往需要對設計策略從根本上進行修改 并發編程的原則和技巧
單一職責原則
分離并發相關代碼和其他代碼(并發相關代碼有自己的開發、修改和調優生命周期)。限制數據作用域
兩個線程修改共享對象的同一字段時可能會相互干擾,導致不可預期的行為,解決方案之一是構造臨界區,但是必須限制臨界區的數量。使用數據副本
數據副本是避免共享數據的好方法,復制出來的對象只是以只讀的方式對待。Java 5的java.util.concurrent包中增加一個名為CopyOnWriteArrayList的類,它是List接口的子類型,所以你可以認為它是ArrayList的線程安全的版本,它使用了寫時復制的方式創建數據副本進行操作來避免對共享數據并發訪問而引發的問題。線程應盡可能獨立
讓線程存在于自己的世界中,不與其他線程共享數據。有過Java Web開發經驗的人都知道,Servlet就是以單實例多線程的方式工作,和每個請求相關的數據都是通過Servlet子類的service方法(或者是doGet或doPost方法)的參數傳入的。只要Servlet中的代碼只使用局部變量,Servlet就不會導致同步問題。springMVC的控制器也是這么做的,從請求中獲得的對象都是以方法的參數傳入而不是作為類的成員,很明顯Struts 2的做法就正好相反,因此Struts 2中作為控制器的Action類都是每個請求對應一個實例。Java 5以前的并發編程
Java的線程模型建立在搶占式線程調度的基礎上,也就是說:
所有線程可以很容易的共享同一進程中的對象。能夠引用這些對象的任何線程都可以修改這些對象。為了保護數據,對象可以被鎖住。
Java基于線程和鎖的并發過于底層,而且使用鎖很多時候都是很萬惡的,因為它相當于讓所有的并發都變成了排隊等待。
在Java 5以前,可以用synchronized關鍵字來實現鎖的功能,它可以用在代碼塊和方法上,表示在執行整個代碼塊或方法之前線程必須取得合適的鎖。對于類的非靜態方法(成員方法)而言,這意味這要取得對象實例的鎖,對于類的靜態方法(類方法)而言,要取得類的Class對象的鎖,對于同步代碼塊,程序員可以指定要取得的是那個對象的鎖。
不管是同步代碼塊還是同步方法,每次只有一個線程可以進入,如果其他線程試圖進入(不管是同一同步塊還是不同的同步塊),JVM會將它們掛起(放入到等鎖池中)。這種結構在并發理論中稱為臨界區(critical section)。這里我們可以對Java中用synchronized實現同步和鎖的功能做一個總結:
只能鎖定對象,不能鎖定基本數據類型 被鎖定的對象數組中的單個對象不會被鎖定
同步方法可以視為包含整個方法的synchronized(this){ ? }代碼塊 靜態同步方法會鎖定它的Class對象 內部類的同步是獨立于外部類的
synchronized修飾符并不是方法簽名的組成部分,所以不能出現在接口的方法聲明中 非同步的方法不關心鎖的狀態,它們在同步方法運行時仍然可以得以運行 synchronized實現的鎖是可重入的鎖。
在JVM內部,為了提高效率,同時運行的每個線程都會有它正在處理的數據的緩存副本,當我們使用synchronzied進行同步的時候,真正被同步的是在不同線程中表示被鎖定對象的內存塊(副本數據會保持和主內存的同步,現在知道為什么要用同步這個詞匯了吧),簡單的說就是在同步塊或同步方法執行完后,對被鎖定的對象做的任何修改要在釋放鎖之前寫回到主內存中;在進入同步塊得到鎖之后,被鎖定對象的數據是從主內存中讀出來的,持有鎖的線程的數據副本一定和主內存中的數據視圖是同步的。
在Java最初的版本中,就有一個叫volatile的關鍵字,它是一種簡單的同步的處理機制,因為被volatile修飾的變量遵循以下規則:
變量的值在使用之前總會從主內存中再讀取出來。對變量值的修改總會在完成之后寫回到主內存中。
使用volatile關鍵字可以在多線程環境下預防編譯器不正確的優化假設(編譯器可能會將在一個線程中值不會發生改變的變量優化成常量),但只有修改時不依賴當前狀態(讀取時的值)的變量才應該聲明為volatile變量。
不變模式也是并發編程時可以考慮的一種設計。讓對象的狀態是不變的,如果希望修改對象的狀態,就會創建對象的副本并將改變寫入副本而不改變原來的對象,這樣就不會出現狀態不一致的情況,因此不變對象是線程安全的。Java中我們使用頻率極高的String類就采用了這樣的設計。如果對不變模式不熟悉,可以閱讀閻宏博士的《Java與模式》一書的第34章。說到這里你可能也體會到final關鍵字的重要意義了。
Java 5的并發編程
不管今后的Java向著何種方向發展或者滅忙,Java 5絕對是Java發展史中一個極其重要的版本,這個版本提供的各種語言特性我們不在這里討論(有興趣的可以閱讀我的另一篇文章《Java的第20年:從Java版本演進看編程技術的發展》),但是我們必須要感謝Doug Lea在Java 5中提供了他里程碑式的杰作java.util.concurrent包,它的出現讓Java的并發編程有了更多的選擇和更好的工作方式。Doug Lea的杰作主要包括以下內容:
更好的線程安全的容器 線程池和相關的工具類 可選的非阻塞解決方案 顯示的鎖和信號量機制
下面我們對這些東西進行一一解讀。
原子類
Java 5中的java.util.concurrent包下面有一個atomic子包,其中有幾個以Atomic打頭的類,例如AtomicInteger和AtomicLong。它們利用了現代處理器的特性,可以用非阻塞的方式完成原子操作,代碼如下所示: /** ID序列生成器 */ public class IdGenerator {
private final AtomicLong sequenceNumber = new AtomicLong(0);
public long next(){
return sequenceNumber.getAndIncrement();
} } 顯示鎖
基于synchronized關鍵字的鎖機制有以下問題:
鎖只有一種類型,而且對所有同步操作都是一樣的作用 鎖只能在代碼塊或方法開始的地方獲得,在結束的地方釋放 線程要么得到鎖,要么阻塞,沒有其他的可能性
Java 5對鎖機制進行了重構,提供了顯示的鎖,這樣可以在以下幾個方面提升鎖機制:
可以添加不同類型的鎖,例如讀取鎖和寫入鎖 可以在一個方法中加鎖,在另一個方法中解鎖
可以使用tryLock方式嘗試獲得鎖,如果得不到鎖可以等待、回退或者干點別的事情,當然也可以在超時之后放棄操作 顯示的鎖都實現了java.util.concurrent.Lock接口,主要有兩個實現類:
ReentrantLock在讀操作很多寫操作很少時性能更好的一種重入鎖
對于如何使用顯示鎖,可以參考我的Java面試系列文章《Java面試題集51-70》中第60題的代碼。只有一點需要提醒,解鎖的方法unlock的調用最好能夠在finally塊中,因為這里是釋放外部資源最好的地方,當然也是釋放鎖的最佳位置,因為不管正常異常可能都要釋放掉鎖來給其他線程以運行的機會。
CountDownLatch
CountDownLatch是一種簡單的同步模式,它讓一個線程可以等待一個或多個線程完成它們的工作從而避免對臨界資源并發訪問所引發的各種問題。下面借用別人的一段代碼(我對它做了一些重構)來演示CountDownLatch是如何工作的。
import java.util.concurrent.CountDownLatch;/** * 工人類
* @author 駱昊
* */ class Worker {
private String name;
// 名字
private long workDuration;// 工作持續時間
/**
* 構造器
*/
public Worker(String name, long workDuration){
this.name = name;
this.workDuration = workDuration;
}
/**
* 完成工作
*/
public void doWork(){
System.out.println(name + “ begins to work...”);
try {
Thread.sleep(workDuration);// 用休眠模擬工作執行的時間
} catch(InterruptedException ex){
ex.printStackTrace();
}
System.out.println(name + “ has finished the job...”);
} } /** * 測試線程
* @author 駱昊
* */ class WorkerTestThread implements Runnable {
private Worker worker;
private CountDownLatch cdLatch;
public WorkerTestThread(Worker worker, CountDownLatch cdLatch){
this.worker = worker;
this.cdLatch = cdLatch;
}
@Override
public void run(){
worker.doWork();
// 讓工人開始工作
cdLatch.countDown();
// 工作完成后倒計時次數減1
} } class CountDownLatchTest {
private static final int MAX_WORK_DURATION = 5000;// 最大工作時間
private static final int MIN_WORK_DURATION = 1000;// 最小工作時間
// 產生隨機的工作時間
private static long getRandomWorkDuration(long min, long max){
return(long)(Math.random()*(max1);// 如果有N個哲學家,最多只允許N-1人同時取叉子
}
/**
* 取得叉子
* @param index 第幾個哲學家
* @param leftFirst 是否先取得左邊的叉子
* @throws InterruptedException
*/
public static void putOnFork(int index, boolean leftFirst)throws InterruptedException {
if(leftFirst){
forks[index].acquire();
forks[(index + 1)% NUM_OF_PHILO].acquire();
}
else {
forks[(index + 1)% NUM_OF_PHILO].acquire();
forks[index].acquire();
}
}
/**
* 放回叉子
* @param index 第幾個哲學家
* @param leftFirst 是否先放回左邊的叉子
* @throws InterruptedException
*/
public static void putDownFork(int index, boolean leftFirst)throws InterruptedException {
if(leftFirst){
forks[index].release();
forks[(index + 1)% NUM_OF_PHILO].release();
}
else {
forks[(index + 1)% NUM_OF_PHILO].release();
forks[index].release();
}
} } /** * 哲學家
* @author 駱昊
* */ class Philosopher implements Runnable {
private int index;
// 編號
private String name;
// 名字
public Philosopher(int index, String name){
this.index = index;
this.name = name;
}
@Override
public void run(){
while(true){
try {
AppContext.counter.acquire();
boolean leftFirst = index % 2 == 0;
AppContext.putOnFork(index, leftFirst);
System.out.println(name + “正在吃意大利面(通心粉)...”);
// 取到兩個叉子就可以進食
AppContext.putDownFork(index, leftFirst);
AppContext.counter.release();
} catch(InterruptedException e){
e.printStackTrace();
}
}
} }
public class Test04 {
public static void main(String[] args){
String[] names = { “駱昊”, “王大錘”, “張三豐”, “楊過”, “李莫愁” };
// 5位哲學家的名字
//
ExecutorService es = Executors.newFixedThreadPool(AppContext.NUM_OF_PHILO);// 創建固定大小的線程池 //
for(int i = 0, len = nawww.tmdps.cnmes.length;i < len;++i){ //
es.execute(new Philosopher(i, names[i]));
// 啟動線程 //
} //
es.shutdown();
for(int i = 0, len = names.length;i < len;++i){
new Thread(new Philosopher(i, names[i])).start();
}
} }
現實中的并發問題基本上都是這三種模型或者是這三種模型的變體。
測試并發代碼
對并發代碼的測試也是非常棘手的事情,棘手到無需說明大家也很清楚的程度,所以這里我們只是探討一下如何解決這個棘手的問題。我們建議大家編寫一些能夠發現問題的測試并經常性的在不同的配置和不同的負載下運行這些測試。不要忽略掉任何一次失敗的測試,線程代碼中的缺陷可能在上萬次測試中僅僅出現一次。具體來說有這么幾個注意事項:
不要將系統的失效歸結于偶發事件,就像拉不出屎的時候不能怪地球沒有引力。先讓非并發代碼工作起來,不要試圖同時找到并發和非并發代碼中的缺陷。編寫可以在不同配置環境下運行的線程代碼。
編寫容易調整的線程代碼,這樣可以調整線程使性能達到最優。
讓線程的數量多于CPU或CPU核心的數量,這樣CPU調度切換過程中潛在的問題才會暴露出來。讓并發代碼在不同的平臺上運行。
通過自動化或者硬編碼的方式向并發代碼中加入一些輔助測試的代碼。Java 7的并發編程
Java 7中引入了TransferQueue,它比BlockingQueue多了一個叫transfer的方法,如果接收線程處于等待狀態,該操作可以馬上將任務交給它,否則就會阻塞直至取走該任務的線程出現。可以用TransferQueue代替BlockingQueue,因為它可以獲得更好的性能。
剛才忘記了一件事情,Java 5中還引入了Callable接口、Future接口和FutureTask接口,通過他們也可以構建并發應用程序,代碼如下所示。
import java.util.ArrayList;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;
public class Test07 {
private static final int POOL_SIZE = 10;
static class CalcThread implements Callable
private List
public CalcThread(){
for(int i = 0;i < 10000;++i){
dataList.add(Math.random());
}
}
@Override
public Double call()throws Exception {
double total = 0;
for(Double d : dataList){
total += d;
}
return total / dataList.size();
}
}
public static void main(String[] args){
List
ExecutorService es = Executors.newFixedThreadPool(POOL_SIZE);
for(int i = 0;i < POOLwww.tmdps.cnpute(){
int sum = 0;
if((end-start)< THRESHOLD){
// 當問題分解到可求解程度時直接計算結果
for(int i = start;i <= end;i++){
sum += i;
}
} else {
int middle =(start + end)>>> 1;
// 將任務一分為二
Calculator left = new Calculator(start, middle);
Calculator right = new Calculator(middle + 1, end);
left.fork();
right.fork();
// 注意:由于此處是遞歸式的任務分解,也就意味著接下來會二分為四,四分為八...sum = left.join()+ right.join();
// 合并兩個子任務的結果
}
return sum;
} }
public class Test08 {
public static void main(String[] args)throws Exception {
ForkJoinPool forkJoinPool = new ForkJoinPool();
Future
System.out.println(result.get());
} }
伴隨著Java 7的到來,Java中默認的數組排序算法已經不再是經典的快速排序(雙樞軸快速排序)了,新的排序算法叫TimSort,它是歸并排序和插入排序的混合體,TimSort可以通過分支合并框架充分利用現代處理器的多核特性,從而獲得更好的性能(更短的排序時間)。
第四篇:java實戰培訓
Java實戰培訓
Java作為全世界使用最廣泛的編程語言,java程序員也是全球最受歡迎的職業之一。java的跨平臺性受到了許多權威機構的肯定,java語言更是在it行業倍受企業的青睞。尚學堂java培訓實戰課程。1-4階段6個真實項目,帶你一步步揭秘java項目實戰編程。讓你從一個菜鳥編程一個編程高手。【培訓項目】
大學生java實戰班,大學生java就業班 【項目案例】
第一階段項目:
CHAT項目 Chat項目通過完成一個模擬的在線聊天系統,主要鍛煉大家對于TCP/IP、Socket編程、C/S模式的編程、線程的運用等方面的能力。
坦克大戰單機版/圖片版/網絡版 這三個項目通過大家喜聞樂見的小游戲的形式來鍛煉大家對于JavaSE綜合運用的能力,并且能夠初步運用面向對象的編程理念,鍛煉初步的設計能力,并基本掌握多線程的編程。
第二階段項目:
BBS的兩個項目完成了一個具備完善前臺展現以及后臺管理的論壇系統,論壇系統的業務邏輯大家比較熟悉,是用來進行JavaWeb開發的極好的入門系統。但是由于其業務邏輯太簡單,尚學堂目前的課程體系中已經用搜索項目來替代它。
第三階段項目:
BBS項目:Credit Control System屬銀行核心業務系統的主要子系統之一,在這個項目中,同學們將鍛煉自己的EJB3.0的知識,同時了解金融方面的知識,做到技術+業務的雙重深入,為以后進入金融行業鋪平道路。
CCS項目:Credit Control System屬銀行核心業務系統的主要子系統之一,在這個項目中,同學們將鍛煉自己的EJB3.0的知識,同時了解金融方面的知識,做到技術+業務的雙重深入,為以后進入金融行業鋪平道路。
第四階段android項目:
樓層日常信息監控系統:本系統是專為大型樓盤與機構等開發的樓層日常信息監控系統,管理人員可以查看室內溫度,室內濕度,UPS,電壓,空調運行情況等,還可以執行空調漏水和電壓報警。本軟件功能:查看室內溫度,室內濕度,UPS,電壓,空調運行情況,空調漏水報警,煙霧探測器等,室內溫度和濕度以及電壓設置報警。本軟件除硬件設備包括服務器的opc探測及傳輸,基礎價為30萬,如需其他功能,價格面議,欲購此軟件的企業請與西安尚學堂聯系。
Android平板電腦移動OA:該軟件可以實現在Android系統的平板電腦上進行客戶管理、日程管理、文件審批、企業通訊錄、郵箱、論壇等功能。
【培訓對象】
1、大專以上學歷,在校大學生或者在職人群;
2、有良好的計算機基礎,能閱讀簡單的英文文檔;
3、有志于從事IT行業。
學校名稱:西安雁塔尚學堂計算機學校 學校網址:www.tmdps.cn
報名熱線:029-82300161
第五篇:Java培訓感言
甲骨文盈佳科技Java培訓感言
為什么要學Java? 首要的原因當然是為了生活,找份好工作。入門學習過程是比較痛苦的,要學好需要一定的努力,但是有一個好處,相對Java來說比較集中,不會出現Java里面這么多差異。Java的學習過程開始比較容易入手,更容易學習。
Java還有一個優勢就是在移動設備的開發,所有的Java應用版本不同,但是語法一致。Java的跨平臺特性可以讓我們在不同的場合下使用。開始的兩年我學Java就是拿書看,練習書上的例子,但是一直沒有好的效果,后來就去甲骨文盈佳科技原廠Java培訓機構進行系統的學習了,畢竟比自學要輕松些,另外還可以學到別人的一些經驗。
學習的過程中不可避免的遇到問題,這些問題有的只是一個符號錯了,一個括號少了,這類的問題在文檔里,或者一般的網站上就能夠找到,尤其是初學者的問題,不會是很難的問題,之前已經有無數人問過了,不要害怕提問,但是這個問題最好是你找不到答案的時候去提。編程是一種樂趣,只有你覺得他有樂趣的時候你才會用更多的熱情去學習,及時總結昨天、做好今天、規劃好明天
感謝甲骨文盈佳科技所有的老師對我的幫助,也祝甲骨文盈佳科技越辦越好