Java工程師就業(yè)前景
Java工程師就業(yè)前景
2015年,在美國、加拿大、澳大利亞、新加坡等發(fā)達(dá)國家和中等發(fā)達(dá)國家,
JAVA軟件工程師年薪均在4—15萬美金,而在國內(nèi),JAVA軟件工程師也有極好的工作機會和很高的薪水。
在未來5年內(nèi),合格軟件人才的需求將遠(yuǎn)大于供給。JAVA軟件工程師是目前
國際高端計算機領(lǐng)域就業(yè)薪資非常高的一類軟件工程師。
一般情況下的JAVA軟件工程師是分四個等級,從軟件技術(shù)員到助理軟件工程
師,再到軟件工程師,**后成為高級軟件工程師。
根據(jù)IDC的統(tǒng)計數(shù)字,在所有軟件開發(fā)類人才的需求中,對JAVA工程師的需
求達(dá)到全部需求量的60%—70%。同時,JAVA軟件工程師的工資待遇相對較高。
通常來說,具有3—5年開發(fā)經(jīng)驗的工程師,擁有年薪15萬元是很正常的一個
薪酬水平。80%的學(xué)生畢業(yè)后年薪都超過了8萬元。
根據(jù)專業(yè)數(shù)據(jù)分析,由于我國經(jīng)濟(jì)發(fā)展不均衡因素,JAVA軟件工程師工資待
遇在城市之間的差異也較大,一級城市(如北京、上海等),初級軟件工程師的待遇大概在4000-6000之間,中級軟件工程師的待遇在6000—8000之間,
而高級軟件工程師的待遇基本破萬。
大數(shù)據(jù)核心知識
Hadoop基礎(chǔ)
Hadoop1介紹
hadoop1架構(gòu)
hadoop2架構(gòu)(對比hadoop1)
hadoop2環(huán)境搭建
HDFS操作
yarn操作
Hadoop應(yīng)用
Hive數(shù)據(jù)倉庫
zookeeper系統(tǒng)服務(wù)
HBase非關(guān)系型數(shù)據(jù)庫
Sqoop數(shù)據(jù)庫抽取工具
Flume日志抽取工具
Spark基礎(chǔ)
環(huán)境搭建
Spark平臺介紹
RDD彈性分布式數(shù)據(jù)集
Scala編程
Spark應(yīng)用
Spark-SQL組件
DataFrame組件
課程優(yōu)勢
1.真實的企業(yè)項目;
2.目前企業(yè)中應(yīng)用廣泛的技術(shù)路線;
3.部分Spark源碼剖析,從源碼層面提升問題解決能力。
4.從hadoop1到hadoop2機制原理詳細(xì)解說;
5.生產(chǎn)環(huán)境hadoop集群調(diào)優(yōu)經(jīng)驗;
6.企業(yè)真實項目實戰(zhàn);
本階段學(xué)習(xí)目標(biāo)
1.了解hadoop機制原理 ;
2.了解hadoop集群搭建過程;
3.了解Hdfs API使用以及mr編程模型;
4.了解hive、hbase、sqoop、flume等組件的使用方法;
5.Spark平臺的優(yōu)勢以及Spark集群的搭建過程;
6.Scala程序設(shè)計基礎(chǔ);
7.Spark-SQL和DataFrame API詳解。
本階段學(xué)習(xí)效果
1.了解hadoop集群的搭建過程;
2.能夠**mr和hive來實現(xiàn)簡單的數(shù)據(jù)清洗的業(yè)務(wù)需求;
3.能夠了解數(shù)據(jù)的抽取,轉(zhuǎn)換,清洗,建模,入庫過程;
4.掌握Spark集群的搭建;
5.掌握函數(shù)式編程思想,能夠根據(jù)業(yè)務(wù)需求編寫高質(zhì)量的Scala程序;
6.掌握大規(guī)模離線數(shù)據(jù)的計算、分析能力。
Java并發(fā)編程:如何創(chuàng)建線程?
>
java并發(fā)編程:如何創(chuàng)建線程?
在前面一篇文章中已經(jīng)講述了在進(jìn)程和線程的由來,今天就來講一下在Java中如何創(chuàng)建線程,讓線程去執(zhí)行一個子任務(wù)。下面先講述一下Java中的應(yīng)用程序和進(jìn)程相關(guān)的概念知識,然后再闡述如何創(chuàng)建線程以及如何創(chuàng)建進(jìn)程。下面是本文的目錄大綱:
一.Java中關(guān)于應(yīng)用程序和進(jìn)程相關(guān)的概念
二.Java中如何創(chuàng)建線程
三.Java中如何創(chuàng)建進(jìn)程
若有不正之處,請多多諒解并歡迎批評指正。
請尊重作者勞動成果,
一.Java中關(guān)于應(yīng)用程序和進(jìn)程相關(guān)的概念
在Java中,一個應(yīng)用程序?qū)?yīng)著一個JVM實例(也有地方稱為JVM進(jìn)程),一般來說名字默認(rèn)為java.exe或者javaw.exe(windows下可以**任務(wù)管理器查看)。Java采用的是單線程編程模型,即在我們自己的程序中如果沒有主動創(chuàng)建線程的話,只會創(chuàng)建一個線程,通常稱為主線程。但是要注意,雖然只有一個線程來執(zhí)行任務(wù),不代表JVM中只有一個線程,JVM實例在創(chuàng)建的時候,同時會創(chuàng)建很多其他的線程(比如垃圾收集器線程)。
由于Java采用的是單線程編程模型,因此在進(jìn)行UI編程時要注意將耗時的操作放在子線程中進(jìn)行,以避免阻塞主線程(在UI編程時,主線程即UI線程,用來處理用戶的交互事件)。
二.Java中如何創(chuàng)建線程
在java中如果要創(chuàng)建線程的話,一般有兩種方式:1)繼承Thread類;2)實現(xiàn)Runnable接口。
1.繼承Thread類
繼承Thread類的話,必須重寫run方法,在run方法中定義需要執(zhí)行的任務(wù)。
1
2
3
4
5
6
7
8
9
10
11
12
|
class MyThread extends Thread{ PRivate static int num = 0 ; public MyThread(){ num ; } @Override public void run() { System.out.println( "主動創(chuàng)建的第" num "個線程" ); } }
|
創(chuàng)建好了自己的線程類之后,就可以創(chuàng)建線程對象了,然后**start()方法去啟動線程。注意,不是調(diào)用run()方法啟動線程,run方法中只是定義需要執(zhí)行的任務(wù),如果調(diào)用run方法,即相當(dāng)于在主線程中執(zhí)行run方法,跟普通的方法調(diào)用沒有任何區(qū)別,此時并不會創(chuàng)建一個新的線程來執(zhí)行定義的任務(wù)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class Test { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } }
class MyThread extends Thread{ private static int num = 0 ; public MyThread(){ num ; } @Override public void run() { System.out.println( "主動創(chuàng)建的第" num "個線程" ); } }
|
在上面代碼中,**調(diào)用start()方法,就會創(chuàng)建一個新的線程了。為了分清start()方法調(diào)用和run()方法調(diào)用的區(qū)別,請看下面一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class Test { public static void main(String[] args) { System.out.println( "主線程ID:" Thread.currentThread().getId()); MyThread thread1 = new MyThread( "thread1" ); thread1.start(); MyThread thread2 = new MyThread( "thread2" ); thread2.run(); } }
class MyThread extends Thread{ private String name; public MyThread(String name){ this .name = name; } @Override public void run() { System.out.println( "name:" name " 子線程ID:" Thread.currentThread().getId()); } }
|
運行結(jié)果:
從輸出結(jié)果可以得出以下結(jié)論:
1)thread1和thread2的線程ID不同,thread2和主線程ID相同,說明**run方法調(diào)用并不會創(chuàng)建新的線程,而是在主線程中直接運行run方法,跟普通的方法調(diào)用沒有任何區(qū)別;
2)雖然thread1的start方法調(diào)用在thread2的run方法前面調(diào)用,但是先輸出的是thread2的run方法調(diào)用的相關(guān)信息,說明新線程創(chuàng)建的過程不會阻塞主線程的后續(xù)執(zhí)行。
2.實現(xiàn)Runnable接口
在Java中創(chuàng)建線程除了繼承Thread類之外,還可以**實現(xiàn)Runnable接口來實現(xiàn)類似的功能。實現(xiàn)Runnable接口必須重寫其run方法。
下面是一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class Test { public static void main(String[] args) { System.out.println( "主線程ID:" Thread.currentThread().getId()); MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); } }
class MyRunnable implements Runnable{ public MyRunnable() { } @Override public void run() { System.out.println( "子線程ID:" Thread.currentThread().getId()); } }
|
Runnable的中文意思是“任務(wù)”,顧名思義,**實現(xiàn)Runnable接口,我們定義了一個子任務(wù),然后將子任務(wù)交由Thread去執(zhí)行。注意,這種方式必須將Runnable作為Thread類的參數(shù),然后**Thread的start方法來創(chuàng)建一個新線程來執(zhí)行該子任務(wù)。如果調(diào)用Runnable的run方法的話,是不會創(chuàng)建新線程的,這根普通的方法調(diào)用沒有任何區(qū)別。
事實上,查看Thread類的實現(xiàn)源代碼會發(fā)現(xiàn)Thread類是實現(xiàn)了Runnable接口的。
在Java中,這2種方式都可以用來創(chuàng)建線程去執(zhí)行子任務(wù),具體選擇哪一種方式要看自己的需求。直接繼承Thread類的話,可能比實現(xiàn)Runnable接口看起來更加簡潔,但是由于Java只允許單繼承,所以如果自定義類需要繼承其他類,則只能選擇實現(xiàn)Runnable接口。
三.Java中如何創(chuàng)建進(jìn)程
在Java中,可以**兩種方式來創(chuàng)建進(jìn)程,總共涉及到5個主要的類。
**種方式是**Runtime.exec()方法來創(chuàng)建一個進(jìn)程,第二種方法是**ProcessBuilder的start方法來創(chuàng)建進(jìn)程。下面就來講一講這2種方式的區(qū)別和聯(lián)系。
首先要講的是Process類,Process類是一個抽象類,在它里面主要有幾個抽象的方法,這個可以**查看Process類的源代碼得知:
位于java.lang.Process路徑下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public abstract class Process { abstract public OutputStream getOutputStream(); abstract public InputStream getInputStream(); abstract public InputStream getErrorStream(); abstract public int waitFor() throws InterruptedException; abstract public int exitValue(); abstract public void destroy(); }
|
1)**ProcessBuilder創(chuàng)建進(jìn)程
ProcessBuilder是一個final類,它有兩個構(gòu)造器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public final class ProcessBuilder { private List<String> command; private File directory; private Map<String,String> environment; private boolean redirectErrorStream; public ProcessBuilder(List<String> command) { if (command == null ) throw new NullPointerException(); this .command = command; } public ProcessBuilder(String... command) { this .command = new ArrayList<String>(command.length); for (String arg : command) this .command.add(arg); } .... }
|
構(gòu)造器中傳遞的是需要創(chuàng)建的進(jìn)程的命令參數(shù),**個構(gòu)造器是將命令參數(shù)放進(jìn)List當(dāng)中傳進(jìn)去,第二構(gòu)造器是以不定長字符串的形式傳進(jìn)去。
那么我們接著往下看,前面提到是**ProcessBuilder的start方法來創(chuàng)建一個新進(jìn)程的,我們看一下start方法中具體做了哪些事情。下面是start方法的具體實現(xiàn)源代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public Process start() throws IOException { String[] cmdarray = command.toArray( new String[command.size()]); for (String arg : cmdarray) if (arg == null ) throw new NullPointerException(); String prog = cmdarray[ 0 ]; SecurityManager security = System.getSecurityManager(); if (security != null ) security.checkExec(prog); String dir = directory == null ? null : directory.toString(); try { return ProcessImpl.start(cmdarray, environment, dir, redirectErrorStream); } catch (IOException e) { throw new IOException( "Cannot run program \"" prog "\"" (dir == null ? "" : " (in directory \"" dir "\")" ) ": " e.getMessage(), e); } }
|
該方法返回一個Process對象,該方法的前面部分相當(dāng)于是根據(jù)命令參數(shù)以及設(shè)置的工作目錄進(jìn)行一些參數(shù)設(shè)定,**重要的是try語句塊里面的一句:
1
2
3
4
|
return ProcessImpl.start(cmdarray, environment, dir, redirectErrorStream);
|
說明真正創(chuàng)建進(jìn)程的是這一句,注意調(diào)用的是ProcessImpl類的start方法,此處可以知道start必然是一個靜態(tài)方法。那么ProcessImpl又是什么類呢?該類同樣位于java.lang.ProcessImpl路徑下,看一下該類的具體實現(xiàn):
ProcessImpl也是一個final類,它繼承了Process類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
final class ProcessImpl extends Process { static Process start(String cmdarray[], java.util.Map<String,String> environment, String dir, boolean redirectErrorStream) throws IOException { String envblock = ProcessEnvironment.toEnvironmentBlock(environment); return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream); } .... }
|
這是ProcessImpl類的start方法的具體實現(xiàn),而事實上start方法中是**這句來創(chuàng)建一個ProcessImpl對象的:
1
|
return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);
|
而在ProcessImpl中對Process類中的幾個抽象方法進(jìn)行了具體實現(xiàn)。
說明事實上**ProcessBuilder的start方法創(chuàng)建的是一個ProcessImpl對象。
下面看一下具體使用ProcessBuilder創(chuàng)建進(jìn)程的例子,比如我要**ProcessBuilder來啟動一個進(jìn)程打開cmd,并獲取ip地址信息,那么可以這么寫:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Test { public static void main(String[] args) throws IOException { ProcessBuilder pb = new ProcessBuilder( "cmd" , "/c" , "ipconfig/all" ); Process process = pb.start(); Scanner scanner = new Scanner(process.getInputStream()); while (scanner.hasNextLine()){ System.out.println(scanner.nextLine()); } scanner.close(); } }
|
**步是**關(guān)鍵的,就是將命令字符串傳給ProcessBuilder的構(gòu)造器,一般來說,是把字符串中的每個獨立的命令作為一個單獨的參數(shù),不過也可以按照順序放入List中傳進(jìn)去。
至于其他很多具體的用法不在此進(jìn)行贅述,比如**ProcessBuilder的environment方法和directory(File directory)設(shè)置進(jìn)程的環(huán)境變量以及工作目錄等,感興趣的朋友可以查看相關(guān)API文檔。
2)**Runtime的exec方法來創(chuàng)建進(jìn)程
首先還是來看一下Runtime類和exec方法的具體實現(xiàn),Runtime,顧名思義,即運行時,表示當(dāng)前進(jìn)程所在的虛擬機實例。
由于任何進(jìn)程只會運行于一個虛擬機實例當(dāng)中,所以在Runtime中采用了單例模式,即只會產(chǎn)生一個虛擬機實例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class Runtime { private static Runtime currentRuntime = new Runtime(); /** * Returns the runtime object associated with the current Java application. * Most of the methods of class <code>Runtime</code> are instance * methods and must be invoked with respect to the current runtime object. * * @return the <code>Runtime</code> object associated with the current * Java application. */ public static Runtime getRuntime() { return currentRuntime; } /** Don t let anyone else instantiate this class */ private Runtime() {} ... }
|
從這里可以看出,由于Runtime類的構(gòu)造器是private的,所以只有**getRuntime去獲取Runtime的實例。接下來著重看一下exec方法 實現(xiàn),在Runtime中有多個exec的不同重載實現(xiàn),但真正**后執(zhí)行的是這個版本的exec方法:
1
2
3
4
5
6
7
|
public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException { return new ProcessBuilder(cmdarray) .environment(envp) .directory(dir) .start(); }
|
可以發(fā)現(xiàn),事實上**Runtime類的exec創(chuàng)建進(jìn)程的話,**終還是**ProcessBuilder類的start方法來創(chuàng)建的。
下面看一個例子,看一下**Runtime的exec如何創(chuàng)建進(jìn)程,還是前面的例子,調(diào)用cmd,獲取ip地址信息:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Test { public static void main(String[] args) throws IOException { String cmd = "cmd " "/c " "ipconfig/all" ; Process process = Runtime.getRuntime().exec(cmd); Scanner scanner = new Scanner(process.getInputStream()); while (scanner.hasNextLine()){ System.out.println(scanner.nextLine()); } scanner.close(); } }
|
要注意的是,exec方法不支持不定長參數(shù)(ProcessBuilder是支持不定長參數(shù)的),所以必須先把命令參數(shù)拼接好再傳進(jìn)去。
關(guān)于在Java中如何創(chuàng)建線程和進(jìn)程的話,暫時就講這么多了,感興趣的朋友可以參考相關(guān)資料、
參考資料:
http://luckykapok918.blog.163.com/blog/static/205865043201210272168556/
http://www.cnblogs.com/ChrisWang/archive/2009/12/02/use-java-lang-process-and-processbuilder-to-create-native-application-process.html
http://lavasoft.blog.51cto.com/62575/15662/
《Java編程思想》
相關(guān)推薦:
蘇州JAVA培訓(xùn) 蘇州JAVA培訓(xùn)班 蘇州JAVA培訓(xùn)機構(gòu)