BaoYaEr
java線程學習
1. 創建線程
Java的線程繼承自Thread的類,處理一個名為run的方法。
class
MyThread
extends
Thread
{
private
int
i
=
0
;
public
void
run()
{
while
(
true
)
{
System.out.println(
++
i);
if
(i
>
100
)
break
;
}
}
}
public
class
program
{
public
static
void
main(String[] args)
{
new
MyThread().start();
}
}
而對于那些不能繼承 Thread 的類,可以采取實現 Runnable 接口的方式進行。
2. 執行權轉交
對于暫時交出執行權,Java 提供了 Thread.yield() 方法.
class
MyThread
extends
Thread
{
public
void
run()
{
int
i
=
0
;
while
(
true
)
{
System.out.println( getName()
+
"
-----------
"
+
(
++
i));
if
(i
>
100
)
break
;
yield();
}
}
}
public
class
ThreadTest
{
public
static
void
main(String[] args)
{
MyThread t1
=
new
MyThread();
MyThread t2
=
new
MyThread();
t1.setName(
"
t1
"
);
t2.setName(
"
t2
"
);
t1.start();
t2.start();
}
}
結果:
t1-----------1
t2-----------1
t1-----------2
t2-----------2
t1-----------3
t2-----------3
t1-----------4
t2-----------4
t1-----------5
t2-----------5
.....
Java 也提供了 Thread.sleep(); 方法,但由于 Thread.sleep 可能被 interrupt( ) 方法中斷,因此必須包含在 try{} 代碼塊中。
class
MyThread
extends
Thread
{
public
void
run()
{
int
i
=
0
;
while
(
true
)
{
System.out.printf(
"
%s=%d\n
"
, getName(),
++
i);
if
(i
>
100
)
break
;
try
{
sleep(
0
);
}
catch
(InterruptedException e)
{
}
}
}
}
public
class
program
{
public
static
void
main(String[] args)
{
MyThread t1
=
new
MyThread();
MyThread t2
=
new
MyThread();
t1.setName(
"
t1
"
);
t2.setName(
"
t2
"
);
t1.start();
t2.start();
}
}
3. 優先級
Java 使用 setPriority( ) 方法調整優先級。
4. 背景線程
Java 使用 setDaemon() 方法。在 Java 中一般將背景線程稱之為"守護線程(daemon thread)"。需要注意的是即便背景線程未結束,進程依然會終止。必須在線程啟動前設置。
5. 線程等待
Java 中都使用 join/Join() 方法阻止調用線程,直到某個線程結束。不過 Java 里面情況還是要復雜一些。當某個線程處于 join 等待時,它可能會被 interrupt( ) 方法中斷,因此也得放在 try{} 代碼塊中。
package
tread;
class
ThreadT
extends
Thread
{
public
boolean
stopFlag
=
false
;
public
void
run()
{
int
i
=
0
;
while
(
!
stopFlag)
{
System.out.println(
++
i);
yield();
}
System.out.println(
"
MyThread over
"
);
}
}
class
JoinThread
extends
Thread
{
public
void
run()
{
ThreadT my
=
new
ThreadT();
my.start();
try
{
my.join();
}
catch
(InterruptedException e)
{
my.stopFlag
=
true
;
System.out.println(
"
JoinThread InterruptedException
"
);
}
}
}
public
class
JoinTest
{
public
static
void
main(String[] args)
{
JoinThread join
=
new
JoinThread();
join.start();
try
{
join.sleep(
100
*
5
);
join.interrupt();
}
catch
(InterruptedException e)
{
//
TODO Auto-generated catch block
e.printStackTrace();
}
}
}
結果:
。。。。。。
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
JoinThread InterruptedException
MyThread over
6. 資源鎖定
Java 提供了 synchronized 關鍵字用來解決多線程資源共享鎖定的問題,synchronized 可用于方法或者某個代碼段。
package
tread;
class
Res
{
String lock
=
""
;
synchronized
static
void
test()
{
for
(
int
i
=
0
; i
<
10
; i
++
)
{
System.out.println( Thread.currentThread().getName()
+
"
=========
"
+
i);
Thread.yield();
}
}
void
test2()
{
synchronized
(lock)
{
for
(
int
i
=
0
; i
<
10
; i
++
)
{
System.out.println( Thread.currentThread().getName()
+
"
========
"
+
i);
Thread.yield();
//
沒有放棄鎖
}
}
}
}
class
MyThreadA
extends
Thread
{
public
void
run()
{
new
Res().test2();
}
}
public
class
SynTest
{
public
static
void
main(String[] args)
{
MyThreadA t1
=
new
MyThreadA();
MyThreadA t2
=
new
MyThreadA();
t1.setName(
"
t1
"
);
t2.setName(
"
t2
"
);
t1.start();
t2.start();
}
}
當我們取消 synchronized 關鍵字時,我們會發現 t1 和 t2 交替執行。添加 synchronized 關鍵字以后,t2 會在 t1 執行完成后執行,因此對于方法的鎖定是成功的。
結果:
t1
========
0
。。。。
t1
========
7
t1
========
8
t1
========
9
t2
========
0
。。。
t2
========
8
t2
========
9
另外,需要注意的是 synchronized 是全局鎖定,也就是說對于靜態方法而言,它們會鎖定全部有此標記的方法(盡管它們不是同一個方法);而對于對象實例,它們會鎖定同一對象全部有此標記的方法(盡管它們不是同一個方法)。
7. 原子操作
所謂原子操作是指不會被線程調度機制打斷的操作;這種操作一旦開始,就一直運行倒結束,中間不會有任何線程切換操作。
通常所說的Java原子操作包括對非long和double型的primitive進行賦值,以及返回這兩者之外的primitive。之所以要把它們排除在外是因為它們都比較大,而JVM的設計規范又沒有要求讀操作和賦值操作必須是原子操作(JVM可以試著去這么作,但并不保證)。不過如果你在long或double前面加了volatile,那么它就肯定是原子操作了。
看下面的例子,雖然 return i是一個原子操作,但是從獲得i的值到方法返回之間有可能被其他線程修改,因此不要主觀的認為下面的操作是原子操作。我們還是有必要為其添加同步關鍵字synchronized。另外 ++i 和 --i 都不是原子操作,它們都涉及讀和寫兩個步驟。
public int getValue() { return i; }
《Thinking in Java》中關于最安全的做法提出了如下的方針,不過我不完全贊同。
如果你要synchronize類的一個方法,索性把所有的方法全都synchronize了。要判斷,哪個方法該synchronize,哪個方法可以不synchronize,通常是很難的,而且也沒什么把握。
刪除synchronized的時候要絕對小心。通常這么做是為了性能,但是synchronized的開銷在JDK1.3和1.4里已經大為降低了。此外,只有在用profiler分析過,確認synchronized確實是瓶頸的前提下才能這么作。
我們順便看看 C# 里面關于原子操作的一些狀況。C# 通過 Interlocked 類來提供原子操作的支持,稱之為互鎖操作。“互鎖操作是原子的 — 即整個操作是不能由相同變量上的另一個互鎖操作所中斷的單元。這在搶先多線程操作系統中是很重要的,在這樣的操作系統中,線程可以在從某個內存地址加載值之后但是在有機會更改和存儲該值之前被掛起。 ”
8. 線程協同
Java用對象鎖來控制多線程安全,而所謂多線程協同無非是利用某種鎖機制讓線程暫時停頓下來,直到某個“信號”發生。為此,Java 將用來進行多線程協同的方法放在了根 Object 上,包括 wait(); notify(); notifyAll(); 。
調用 wait() / notify() / notifyAll() 之前必須先獲取其對象鎖,否則會拋出"IllegalMonitorStateException - current thread not owner" 異常。
package
tread;
class
MyThread
extends
Thread
{
static
Object o
=
new
Object();
public
void
run()
{
synchronized
(o)
{
int
i
=
0
;
while
(
++
i
<
10
)
{
System.out.println(i);
try
{
if
(i
==
5
) o.wait();
}
catch
(InterruptedException e)
{
}
}
}
}
}
public
class
SynTest2
{
public
static
void
main(String[] args)
{
MyThread t1
=
new
MyThread();
t1.start();
while
(t1.getState()
!=
Thread.State.WAITING)
{
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e)
{
}
}
System.out.println(
"
Notify Thread
"
);
synchronized
(MyThread.o)
{
MyThread.o.notify();
}
}
}
輸出
1
2
3
4
5
Notify Thread...
6
7
8
9
在上面這個例子中,當 i 等于 5 時,我們調用了對象鎖 o 的 wait 方法阻塞線程。在 main 方法中我們循環檢查對象狀態,并適時發出信號結束等待。這個例子雖然很簡單,但是由此可以處理多個線程之間的協同關系。當然,我們還可以給 wait 方法加一個參數,讓其等待特定的時間,而不是上面例子中的無限制等待。
需要注意的是 wait() 會釋放對象鎖,sleep() 則不會。接著看下面的例子。
class MyThread extends Thread {
static Object o = new Object();
public void run() {
synchronized (o) {
int i = 0;
while (++i < 10) {
System.out.printf("%s - %d\n", Thread.currentThread().getName(), i);
try
{
if (i >= 5) o.wait();
}
catch (InterruptedException e)
{
}
}
}
}
}
public class Program {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
輸出
t1 - 1
t1 - 2
t1 - 3
t1 - 4
t1 - 5
t2 - 1
t2 - 2
t2 - 3
t2 - 4
t2 - 5
9. 停止/中斷線程
線程退出最好自己實現,在運行狀態中一直檢驗一個狀態,如果這個狀態為真,就一直運行,如果外界更改了這個狀態變量,那么線程就停止運行。
Java 不推薦使用 stop() / about() / suspend() / resume() 之類的方法來停止線程。原因包括:
在調用這些方法的時候,我們不能確定線程方法執行到何處,是否完成了特定的邏輯。
這些方法會讓線程無法正確釋放對象鎖,可能造成死鎖。
推薦的方法:
使用旗標(flag)。
調用 interrupt()。
class MyThread extends Thread {
public boolean stopFlag = false;
public void run() {
while (!stopFlag) {
try
{
System.out.println("Thread running, " + System.currentTimeMillis());
Thread.sleep(50);
}
catch (Exception e)
{
}
}
System.out.println("Thread Stop...");
}
}
public class Program {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
try
{
Thread.sleep(100);
}
catch (Exception e)
{
}
t.stopFlag = true;
}
}
當線程因某種原因處于阻塞等待狀態時,我們就無法使用旗標終止它,那么改用interrupt()好了。
class MyThread extends Thread {
public void run() {
try
{
while (true) {
System.out.println("Thread running, " + System.currentTimeMillis());
synchronized (this) {
wait();
}
}
}
catch (Exception e)
{
}
System.out.println("Thread Stop...");
}
}
public class Program {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
try
{
while (t.getState() != Thread.State.WAITING) {
Thread.sleep(500);
}
t.interrupt();
}
catch (Exception e)
{
}
}
}
發表于 2007-04-11 16:24
大田斗
閱讀(736)
評論(0)
編輯
收藏
所屬分類:
java
新用戶注冊
刷新評論列表
只有注冊用戶
登錄
后才能發表評論。
網站導航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
相關文章:
mule事件驅動服務
JDK1.5中的線程池(java.util.concurrent.ThreadPoolExecutor)使用簡介
在xml的汪洋中遨游之mule篇
linux下java運行腳本
深入淺出之正則表達式【zt】
JavaClassLoader與Package機制
JTA事務初級研究
Spring2.5注釋語法
java annotation
J2SE5.0中最有趣的新特性:注釋(annotation) [zt]
<
2025年5月
>
日
一
二
三
四
五
六
27
28
29
30
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
1
2
3
4
5
6
7
導航
BlogJava
首頁
發新隨筆
發新文章
聯系
聚合
管理
統計
隨筆: 32
文章: 427
評論: 144
引用: 0
常用鏈接
我的隨筆
我的評論
我的參與
最新評論
留言簿
(5)
給我留言
查看公開留言
查看私人留言
隨筆檔案
2008年12月 (1)
2008年4月 (2)
2008年2月 (1)
2008年1月 (1)
2007年12月 (3)
2007年11月 (1)
2007年10月 (3)
2007年7月 (2)
2007年6月 (1)
2007年4月 (2)
2007年3月 (3)
2007年2月 (5)
2007年1月 (3)
2006年12月 (4)
文章分類
axis(6)
(rss)
eclipse(7)
(rss)
Hibernate(30)
(rss)
html/js/css(107)
(rss)
java(106)
(rss)
linux(7)
(rss)
Lucene(7)
(rss)
spring(36)
(rss)
Spring CLOUd(1)
(rss)
Strtus(30)
(rss)
其它(48)
(rss)
開源opensource(48)
(rss)
數據庫DateBase(30)
(rss)
設計模式(12)
(rss)
文章檔案
2018年8月 (1)
2012年5月 (1)
2012年4月 (2)
2011年7月 (6)
2010年3月 (1)
2010年2月 (1)
2010年1月 (3)
2009年12月 (1)
2009年10月 (1)
2009年8月 (3)
2009年3月 (1)
2009年2月 (1)
2008年12月 (3)
2008年11月 (10)
2008年10月 (3)
2008年9月 (2)
2008年8月 (2)
2008年7月 (4)
2008年6月 (13)
2008年5月 (15)
2008年4月 (9)
2008年3月 (10)
2008年1月 (18)
2007年12月 (33)
2007年11月 (6)
2007年10月 (18)
2007年9月 (10)
2007年8月 (18)
2007年7月 (15)
2007年6月 (25)
2007年5月 (19)
2007年4月 (26)
2007年3月 (38)
2007年2月 (33)
2007年1月 (27)
2006年12月 (27)
2006年11月 (12)
java
Ajax特效網站
cndiy nio
GRO
Hani Suleiman's blog
Java之路
java論壇
J道
mule
mule 入門
oksonic(動畫教程)
一路由你
中國eclipse
八進制
在線源碼
多線程實戰
天火
小米的blogjava
幻境伯克----jface/swt
很全的博克-強
每日一得
滿江紅
邢紅瑞
飛翔
鳥詩選(js)
鳥食軒 (dhtml)
工具
apache中文手冊
extjs學習
iconFindre
java 安全
javaresearch
java技巧網
js之王
matrix(study)
prototype api
spring中文
北京IT企業速查
在線流程圖工具
雅虎翻譯
朋友
Happyshow
hibernate異常
skywalker
sunshow
xf
亞光
同云博客
小弟鵬
張玉磊
昕
李陽
黃鳴
搜索
積分與排名
積分 - 1101551
排名 - 28
最新評論
1.?re: hibernate.cfg.xml配置
好全啊 .. 棒棒噠 ~ !
--junqinag.yang
2.?re: Quartz任務調度快速入門
我現在來看還是覺得不錯
--小任
3.?re: js中this的總結
評論內容較長,點擊標題查看
--pam
4.?re: Quartz任務調度快速入門
樓主辛苦
--yd
5.?re: Quartz任務調度快速入門
頂了,內容寫的很好
--sen
閱讀排行榜
1.?網頁不緩存(3552)
2.?Form嵌套引起的問題 (2849)
3.?解決IE下CSS背景圖片閃爍的Bug(2445)
4.?Spring AOP的動態載入原理(2403)
5.?如何制作漂亮的Excel表格(2044)
評論排行榜
1.?北京戶口--吃官司(5)
2.?開始→運行→輸入的命令集錦(3)
3.?讓網頁上的所有圖片動起來(2)
4.?Dom4j 編碼問題徹底解決 (1)
5.?心情不爽(1)
Powered by:
博客園
模板提供:
滬江博客
Copyright ©2025 大田斗
主站蜘蛛池模板:
激情小说亚洲色图
|
久久免费线看线看
|
国产亚洲精AA在线观看SEE
|
免费无码成人AV在线播放不卡
|
波多野结衣亚洲一级
|
亚洲午夜无码AV毛片久久
|
最近免费2019中文字幕大全
|
亚洲AV第一成肉网
|
亚洲人成亚洲精品
|
亚洲av中文无码
|
99久久国产热无码精品免费
|
日韩精品无码免费视频
|
亚洲日韩乱码久久久久久
|
免费中文字幕在线
|
18禁免费无码无遮挡不卡网站
|
欧洲美女大片免费播放器视频
|
亚洲欧洲国产成人精品
|
中文亚洲AV片在线观看不卡
|
免费a级毛片无码a∨蜜芽试看
|
a毛片在线看片免费
|
亚洲国产精品99久久久久久
|
久久久无码精品亚洲日韩按摩
|
久久亚洲精品无码VA大香大香
|
免费一级国产生活片
|
国产a视频精品免费观看
|
中文成人久久久久影院免费观看
|
亚洲精品无码久久久久牙蜜区
|
亚洲一级二级三级不卡
|
亚洲日本韩国在线
|
日本xxwwxxww在线视频免费
|
xxxx日本免费
|
久热免费在线视频
|
三上悠亚在线观看免费
|
免费人成视频在线播放
|
亚洲一卡2卡3卡4卡5卡6卡
|
亚洲系列国产精品制服丝袜第
|
国产亚洲成av人片在线观看
|
亚洲精品乱码久久久久久不卡
|
精品国产一区二区三区免费看
|
2021久久精品免费观看
|
久久ww精品w免费人成
|