其然IT教育集團(tuán)是廣州騰科網(wǎng)絡(luò)技術(shù)有限公司旗下運(yùn)營的網(wǎng)站平臺。其然IT
教育集團(tuán)是一家以提供新型、**的IT技術(shù)培訓(xùn)(教育)解決方案為主要經(jīng)營目標(biāo)的專業(yè)公司,是中國高端IT培訓(xùn)的**品牌。聯(lián)合思科(Cisco)、甲
骨文(Oracle)、紅帽(Red Hat)、華為(Huawei)、微軟(Microsoft)、美國計(jì)算機(jī)行業(yè)協(xié)會(CompTIA)等國際知名IT廠商以 及國內(nèi)300多家高等院校,
開展IT認(rèn)證技能培訓(xùn)和IT職業(yè)課程教育,培養(yǎng)新型IT高級人才,是Pearson VUE國際電子考試中心和Prometric(普爾文)授權(quán)考試中心,并是達(dá)索
(solidworks)、安氏(LinkTrust)的授權(quán)經(jīng)銷商。
其然IT教育集團(tuán)下轄上海分公司、深圳分公司、武漢分公司、杭州分公司等
8個(gè)分支機(jī)構(gòu)。以及30多個(gè)培訓(xùn)網(wǎng)點(diǎn),業(yè)務(wù)涵蓋全國主要大、中型城市。
Java培訓(xùn)Java與自學(xué)Java的差距
培訓(xùn)Java與自學(xué)Java的差距
我以前也是自學(xué)Java,在一家公司跟著別人學(xué),以前是別人眼中的菜鳥,現(xiàn)
在是別人眼中的大神,Java很簡單的,貴在堅(jiān)持和多練,沒必要花那培訓(xùn)錢。如果真的要去學(xué)的話,
選擇Java培訓(xùn)機(jī)構(gòu)要注意這兩點(diǎn)基本上就能避免一些坑:
1. 老師沒有正經(jīng)公司工作經(jīng)歷,或者沒有已經(jīng)在線上正常運(yùn)轉(zhuǎn)的產(chǎn)品。一
些所謂培訓(xùn)班的老師水平往往比較一般,甚至還有培訓(xùn)出來后又接著培訓(xùn)別人的。
2、是不是會承諾幫你找到工作,要找到好的工作,不是靠別人給你保證的
,還是要靠自己提升能力。
建議多自己學(xué)習(xí)加上找些好的代碼主動(dòng)學(xué)習(xí)。例如github,多練習(xí)網(wǎng)上很多
網(wǎng)站里真正好的代碼。作為Java工程師,可以多看看spring文檔,看看很多已經(jīng)成熟的框架,深入去體會。另外,學(xué)軟件等等**好還是自己多學(xué),找點(diǎn)
視頻教程之類,也省點(diǎn)錢。
JavaWeb開發(fā)
-
01HTML5與CSS3
-
1.B/S架構(gòu)
-
2.HTML基本使用
-
3.HTML DOM
-
4.CSS選擇器
-
5.常用樣式
-
6.盒子模型與布局
-
7.HTML5新特性
-
8.CSS3新特性
-
02JavaScript
-
03jQuery
-
1.jQuery快速入門
-
2.jQuery語法詳解
-
3.jQuery核心函數(shù)
-
4.jQuery對象/JavaScript對象
-
5.jQuery選擇器
-
6.jQuery 文檔處理
-
7.jQuery事件
-
8.jQuery動(dòng)畫效果
-
04AJAX&JSON
-
05XML
-
1.XML用途
-
2.XML文檔結(jié)構(gòu)
-
3.XML基本語法
-
4.DOM&SAX解析體系
-
5.DOM4j節(jié)點(diǎn)查詢
-
6.DOM4j文檔操作
-
7.xPath語法
-
8.xPath快速查詢
-
06bootstrap
-
1.bootstrap快速使用
-
2.柵格系統(tǒng)
-
3.表單、表格、按鈕、圖片
-
4.下拉菜單
-
5.按鈕組使用
-
6.導(dǎo)航條
-
7.分頁、進(jìn)度條
-
07Web服務(wù)器基礎(chǔ)
-
1.HTTP協(xié)議
-
2.HttpWatch
-
3.Tomcat服務(wù)器搭建
-
4.Tomcat目錄結(jié)構(gòu)解析
-
5.Tomcat端口配置
-
6.Tomcat啟動(dòng)&停止
-
7.Tomcat&Eclipse整合
-
8.Eclipse配置優(yōu)化
-
08Servlet
-
09JSP
-
1.JSP語法
-
2.JSP原理
-
3.JSP腳本片段&表達(dá)式
-
4.JSP聲明&指令
-
5.JSP九大隱含對象
-
6.域?qū)ο笫褂?/span>
-
10JSTL
-
1.JSTL簡介
-
2.JSTL-核心標(biāo)簽庫
-
3.JSTL-函數(shù)標(biāo)簽庫
-
4.JSTL-fmt標(biāo)簽庫
-
5.自定義標(biāo)簽庫使用
-
6.自定義標(biāo)簽庫原理
-
11EL
-
1.EL表達(dá)式簡介
-
2.EL使用
-
3.EL取值原理
-
4.EL的11大隱含對象
-
5.EL2.2與3.0規(guī)范
-
6.EL邏輯運(yùn)算
-
7.函數(shù)庫深入
-
12Cookie&Session
-
1.Cookie機(jī)制
-
2.Cookie創(chuàng)建&使用
-
3.Session原理
-
4.Session失效
-
5.Url重寫
-
6.Session活化&鈍化
-
7.Token令牌應(yīng)用
-
13Filter&Listener
-
1.Filter原理
-
2.Filter聲明周期
-
3.Filter鏈
-
4.Filter登錄驗(yàn)證
-
5.Filter事務(wù)控制
-
6.Listener原理
-
7.八大監(jiān)聽器使用
-
8.Listener監(jiān)聽在線用戶
-
14國際化
-
1.國際化原理
-
2.ResourceBundle&Locale
-
3.國際化資源文件
-
4.日期/數(shù)字/貨幣國際化
-
5.頁面動(dòng)態(tài)中英文切換
-
6.頁面點(diǎn)擊鏈接中英文切換
-
7.fmt標(biāo)簽庫的使用
-
15文件上傳
JAVA并發(fā)編程-線程間協(xié)作(Object監(jiān)視器方法與Condition)
>
原文地址http://blog.csdn.net/zhshulin/article/details/50762465
說到線程間協(xié)作,不得不提到經(jīng)典的生產(chǎn)者與消費(fèi)者模型:有一個(gè)商品隊(duì)列,生產(chǎn)者想隊(duì)列中添加商品,消費(fèi)者取出隊(duì)列中的商品;顯然,如果隊(duì)列為空,消費(fèi)者應(yīng)該等待生產(chǎn)者產(chǎn)生商品才能消費(fèi);如果隊(duì)列滿了,生產(chǎn)者需要等待消費(fèi)者消費(fèi)之后才能生產(chǎn)商品。隊(duì)列就是這個(gè)模型中的臨界資源,當(dāng)隊(duì)列為空時(shí),而消費(fèi)者獲得了該對象的鎖,如果不釋放,那么生產(chǎn)者無法獲得對象鎖,而消費(fèi)者無法消費(fèi)對象,就進(jìn)入了死鎖狀態(tài);反之隊(duì)列滿時(shí),生產(chǎn)者不釋放對象鎖也會造成死鎖。這是我們不希望看到的,所以就有了線程間協(xié)作來解決這個(gè)問題。
其實(shí)說到生產(chǎn)者與消費(fèi)者模型,我們不能簡單的知道怎么實(shí)現(xiàn),而是需要知這種模型的使用場景:主要是為了復(fù)用和解耦,常見的消息框架(非常經(jīng)典的一種生產(chǎn)者消費(fèi)者模型的使用場景)ActiveMQ。發(fā)送端和接收端用Topic進(jìn)行關(guān)聯(lián)。
java語言中,如何實(shí)現(xiàn)線程間協(xié)作呢?比較常見的方法就是利用Object.wait(),Object.notify()和Condition。
先看看這幾個(gè)方法究竟有什么作用?為什么利用它們就可以實(shí)現(xiàn)線程間協(xié)作了呢?
首先分析一下wait()/notify()/notifyAll()這三個(gè)Object監(jiān)視器方法,比較早的方法,JDK1.5之前:
1、上述三個(gè)方法都是Object類中的本地方法,且為final,無法被重寫;且這三個(gè)方法都必須在同步塊或者同步方法中才能執(zhí)行;
2、當(dāng)前線程必須擁有該對象的鎖,才能執(zhí)行wait()方法,wait()方法會阻塞當(dāng)前線程,并且釋放對象鎖;
3、notify()方法可以喚醒一個(gè)(1/N)正在等待這個(gè)資源鎖的線程,但是不保證被喚醒的線程一定可以獲得這個(gè)對象鎖。
4、notifyAll()方法可以喚醒所有正在等待這個(gè)資源鎖的線程,然后讓它們?nèi)ジ偁庂Y源鎖,具體哪個(gè)能拿到就不知道了。
下面看如何使用上述的wait()和notify()方法來實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者模式:
[java] view
plain copy
PRint?
package org.zsl.learn.thread.join;
import java.util.PriorityQueue;
public class Producer implements Runnable{
private PriorityQueue<Integer> queue = null;
private int queueSize =0;
public Producer(PriorityQueue<Integer> queue,int queueSize){
this.queue=queue;
this.queueSize=queueSize;
}
public void product(){
while(true){
synchronized (queue) {
System.out.println("當(dāng)前隊(duì)列中數(shù)據(jù)數(shù)量是:" queue.size());
while(queue.size()==queueSize){//對于生產(chǎn)者來說需要判斷的是隊(duì)列是否滿了,如果滿了就等待
System.out.println("隊(duì)列已滿,等待消費(fèi)者消費(fèi)....");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify(); //這里為什么加個(gè)notify呢?是為了防止死鎖,線程出現(xiàn)問題時(shí),也要釋放對象鎖。
}
}
//如果隊(duì)列沒滿,那么就往隊(duì)列中加入數(shù)據(jù)
queue.offer(1);
queue.notify();
try {
Thread.sleep(100); //為什么加個(gè)休眠?是為了讓我們可以在控制臺看到生產(chǎn)者和消費(fèi)者交替執(zhí)行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("向隊(duì)列中插入一個(gè)數(shù)據(jù),隊(duì)列中剩余空間是:" (queueSize-queue.size()));
}
}
}
@Override
public void run() {
this.product();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join;
import java.util.PriorityQueue;
public class Consumer implements Runnable{
private PriorityQueue<Integer> queue = null;
public Consumer(PriorityQueue<Integer> queue){
this.queue=queue;
}
private void consume(){
while(true){
synchronized (queue) { //首先鎖定對象
//如果隊(duì)列為空,那么消費(fèi)者無法消費(fèi),必須等待生產(chǎn)者產(chǎn)生商品,所以需要釋放對象鎖,并讓自己進(jìn)入等待狀態(tài)
System.out.println("當(dāng)前隊(duì)列中剩余數(shù)據(jù)個(gè)數(shù):" queue.size());
while(queue.size()==0) {
System.out.println("隊(duì)列為空,等待數(shù)據(jù)......");
try {
queue.wait(); //使用wait()這個(gè)方法的時(shí)候,對象必須是獲取鎖的狀態(tài),調(diào)用了這個(gè)方法后,線程會釋放該對象鎖
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();//這里為什么加個(gè)notify呢?是為了防止死鎖,線程出現(xiàn)問題時(shí),也要釋放對象鎖。
}
}
//如果不為空,取出**個(gè)對象
queue.poll();
//注意notify()方法就是釋放這個(gè)對象的鎖,從而其他需要這個(gè)對象的線程中就會有一個(gè)能夠獲得鎖,但是不能指定具體的線程
queue.notify();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("消費(fèi)一個(gè)數(shù)據(jù)后,隊(duì)列中剩余數(shù)據(jù)個(gè)數(shù):" queue.size());
}
}
}
@Override
public void run() {
this.consume();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join;
import java.util.PriorityQueue;
public class Test {
public static void main(String[] args) {
int queueSize = 20;
//這里可以回憶一下JVM中多線程共享內(nèi)存的知識
PriorityQueue<Integer> queue = new PriorityQueue<>(queueSize);
Consumer consumer = new Consumer(queue);
Producer producer = new Producer(queue, queueSize);
new Thread(consumer).start();
new Thread(producer).start();
}
}
-----------------------------------------------------------------------------------------------------
下面我們再來分析一下JAVA中的Condition又是什么呢?java.util.concurrent.locks.Condition是為了替代Object監(jiān)視器方法。那么我們不經(jīng)就要問:Condition相比較Object監(jiān)視器的三個(gè)方法有什么差別呢?下面我們就來對比看看,到底差別在哪里?下面這個(gè)表展示了它們方法之間的共性。
|
Object
|
Condititon
|
休眠
|
wait
|
await
|
喚醒一個(gè)線程
|
notify
|
signal
|
喚醒所有線程
|
notifyAll
|
signalAll
|
使用Condition中,使用Lock來替代Synchronized關(guān)鍵字來實(shí)現(xiàn)操作的原子性,實(shí)現(xiàn)對臨界資源的加鎖與解鎖,同樣的,Condition中提供的三個(gè)方法也需要在“同步塊”中進(jìn)行。Condition相比較而言,強(qiáng)大的地方在于它能夠精確的控制多線程的休眠與喚醒(注意是喚醒,喚醒并不表示該線程一定能夠得到資源鎖),這個(gè)意思就是有A/B/C/D四個(gè)線程共享Z資源,如果A占用了Z,并且調(diào)用了b_condition.notify()就可以釋放資源喚醒B線程,而Object的nofity就無法保證B/C/D中會被喚醒哪一個(gè)了。其實(shí)多數(shù)線程間協(xié)作實(shí)用上述兩種方式都可以實(shí)現(xiàn),但是Sun推薦使用Condition來實(shí)現(xiàn)...我認(rèn)為具體看你喜歡了,以及使用的熟練程度,除非你特別希望精確控制哪個(gè)線程被喚醒。
[java] view
plain copy
print?
package org.zsl.learn.thread.join2;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Producer2 implements Runnable{
private PriorityQueue<Integer> queue = null;
private int queueSize =0;
private Lock lock = null;
private Condition consume=null;
private Condition produce=null;
public Producer2(PriorityQueue<Integer> queue,int queueSize,Lock lock,Condition produce,Condition consume){
this.queue=queue;
this.queueSize=queueSize;
this.lock=lock;
this.consume=consume;
this.produce=produce;
}
public void product(){
while(true){
lock.lock();
try{
while(queue.size()==queueSize){
System.out.println("隊(duì)列滿了,等待消費(fèi)者消費(fèi)...");
try {
produce.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
consume.signal();
}
}
queue.offer(1);
System.out.println("向隊(duì)列中插入了一個(gè)對象,隊(duì)列的剩余空間是:" (queueSize-queue.size()));
consume.signal();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}finally{
lock.unlock();
}
}
}
@Override
public void run() {
this.product();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join2;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Consumer2 implements Runnable{
private PriorityQueue<Integer> queue = null;
private Lock lock = null;
private Condition consume=null;
private Condition produce=null;
public Consumer2(PriorityQueue<Integer> queue,Lock lock,Condition produce,Condition consume){
this.queue=queue;
this.lock =lock;
this.consume = consume;
this.produce = produce;
}
private void consume(){
while(true){
lock.lock();
try{
while(queue.size()==0){
System.out.println("隊(duì)列為空,等待數(shù)據(jù)...");
try {
consume.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
produce.signal();
}
}
queue.poll();
System.out.println("從隊(duì)列中取出一個(gè)元素,隊(duì)列剩余數(shù)量是:" queue.size());
produce.signal();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}finally{
lock.unlock();
}
}
}
@Override
public void run() {
this.consume();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join2;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
public static void main(String[] args) {
int queueSize = 20;
PriorityQueue<Integer> queue = new PriorityQueue<>(queueSize);
Lock lock = new ReentrantLock();
Condition produce = lock.newCondition();
Condition consume = lock.newCondition();
Consumer2 consumer2 = new Consumer2(queue,lock,produce,consume);
Producer2 producer2 = new Producer2(queue, queueSize,lock,produce,consume);
new Thread(consumer2).start();
new Thread(producer2).start();
}
}
其實(shí)在上述兩個(gè)代碼的實(shí)現(xiàn)結(jié)果中,如果不加上Thread.sleep()來讓線程睡眠,我們看到的結(jié)果就像是單線程一樣,生產(chǎn)者填滿隊(duì)列,消費(fèi)者清空隊(duì)列。為什么會這樣呢?我們注意到,在“同步塊”中,如果不是隊(duì)列的臨界值(0、maxSize),僅僅是調(diào)用notify來喚醒一個(gè)等待該資源的線程,那么這個(gè)線程本身并沒有進(jìn)入等待狀態(tài),這個(gè)線程在釋放這個(gè)鎖之后會加入這個(gè)鎖的競爭中,到底誰得到這個(gè)鎖,其實(shí)也說不清楚,修改sleep的睡眠時(shí)間,可以看到從100毫秒到2000毫秒,設(shè)置不同的休眠時(shí)間,可以觀察到生產(chǎn)者與消費(fèi)者也不會出現(xiàn)交替進(jìn)行,還是隨機(jī)的。那么為什么要用Condition實(shí)現(xiàn)對確定線程的喚醒操作呢?喚醒了又不一定得到鎖,這個(gè)需要使用到await()來讓當(dāng)前線程必須等到其他線程來喚醒才能控制生產(chǎn)者與消費(fèi)者的交替執(zhí)行。大家可以嘗試一下:
在produce.signal()和consume.signal后面分別加上:consume.await()和produce.await即可實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者(多個(gè)線程也可以控制任意兩個(gè)線程交替執(zhí)行)的交替執(zhí)行,這個(gè)呢,使用Object監(jiān)視器方法在多個(gè)線程的情況下是不可能實(shí)現(xiàn)的,但是僅僅2個(gè)線程還是可以的。上述列子中,如果有多個(gè)消費(fèi)者,那么如何在生產(chǎn)者完成生產(chǎn)后就只喚醒消費(fèi)者線程呢?同樣,用Condition實(shí)現(xiàn)就非常簡單了,如果使用Object監(jiān)視器類也可以實(shí)現(xiàn),大家不妨想一下,但是相對復(fù)雜,編程過程中容易出現(xiàn)死鎖。
相關(guān)推薦:
蘇州JAVA培訓(xùn) 蘇州JAVA培訓(xùn)班 蘇州JAVA培訓(xùn)機(jī)構(gòu)
體驗(yàn)課預(yù)約試聽
倒計(jì)時(shí)
12:00:00