Tải bản đầy đủ (.pdf) (23 trang)

Tài liệu Java : Đa tuyến pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (380.32 KB, 23 trang )

41
A TUYN
Mc tiêu:
Sau khi kt thúc ching này, bn có th:
 nh ngha mt lung
 Mô t đa tuyn
 To và qun lý lung
 Hiu đc vòng đi ca lung
 Mô t mt lung him
 Gii thích tp hp các lung u tiên nh th nào
 Gii thích đc s cn thit ca s đng b
 Hiu đc cách thêm vào các t khoá synchronized (đng b) nh th
nào
 Lit kê nhng điu không thun li ca s đng b
 Gii thích vai trò ca các phng thc wait() (đi), notify() (thông
báo) và notifyAll().
 Mô t mt điu kin b tc (deadlock).
1. Gii thiu
Mt lung là mt thuc tính duy nht ca Java. Nó là đn v nh nht ca đon
mã có th thi hành đc mà thc hin mt công vic riêng bit. Ngôn ng Java và máy o
Java c hai là các h thng đc phân lung
2. a tuyn
Java h tr đa tuyn, mà có kh nng làm vic vi nhiu lung. Mt ng dng có
th bao hàm nhiu lung. Mi lung đc đng ký mt công vic riêng bit, mà chúng
đc thc thi đng thi vi các lung khác.
a tuyn gi thi gian nhàn ri ca h thng thành nh nht. iu này cho phép
bn vit các chng trình có hiu qu cao vi s tn dng CPU là ti đa. Mi phn ca
chng trình đc gi mt lung, mi lung đnh ngha mt đng dn khác nhau ca s
thc hin. ây là mt thit k chuyên dùng ca s đa nhim.
Trong s đa nhim, nhiu chng chng trình chy đng thi, mi chng trình
có ít nht mt lung trong nó. Mt vi x lý thc thi tt c các chng trình. Cho dù nó có


th xut hin mà các chng trình đã đc thc thi đng thi, trên thc t b vi x lý
nhy qua li gia các tin trình.
3. To và qun lý lung
Khi các chng trình Java đc thc thi, lung chính luôn luôn đang đc thc
hin. ây là 2 nguyên nhân quan trng đi vi lung chính:
 Các lung con s đc to ra t nó.
 Nó là lung cui cùng kt thúc vic thc hin. Trong chc lát lung
chính ngng thc thi, chng trình b chm dt.
Cho dù lung chính đc to ra mt cách t đng vi chng trình thc thi, nó có
th đc điu khin thông qua mt lung đi tng.
Các lung có th đc to ra t hai con đng:
 Trình bày lp nh là mt lp con ca lp lung, ni mà phng thc run() ca
lp lung cn đc ghi đè. Ly ví d:
42
Class Mydemo extends Thread
{
//Class definition
public void run()
{
//thc thi
}
}
 Trình bày mt lp mà lp này thc hin lp Runnable. Ri thì đnh ngha
phng thc run().
Class Mydemo implements Runnable
{
//Class definition
public void run()
{
//thc thi

}
}
Chng trình 8.1 s ch ra s điu khin lung chính nh th nào
Chng trình 8.1
import java.io.*;
public class Mythread extends Thread{
/**
* Mythread constructor comment.
*/
public static void main(String args[]){
Thread t = Thread.currentThread();
System.out.println("The current Thread is :" + t);
t.setName("MyJavaThread");
System.out.println("The thread is now named: " + t);
try{
for(int i = 0; i <3;i++){
System.out.println(i);
Thread.sleep(1500);
}
}catch(InterruptedException e){
System.out.println("Main thread interupted");
}
}
}
Hình sau đây s ch ra kt qu xut ra màn hình ca chng trình trên
43

Hình 8.1 Lung
Trong kt qu xut ra  trên










Mi lung trong chng trình Java đc đng ký cho mt quyn u tiên. Máy o
Java không bao gi thay đi quyn u tiên ca lung. Quyn u tiên vn còn là hng s
cho đn khi lung b ngt.
Mi lung có mt giá tr u tiên nm trong khong ca mt
Thread.MIN_PRIORITY ca 1, và mt Thread.MAX_PRIORITY ca 10. Mi lung ph
thuc vào mt nhóm lung, và mi nhóm lung có quyn u tiên ca chính nó. Mi
lung đc nhn mt hng s u tiên ca phng thc Thread.PRIORITY là 5. Mi
lung mi tha k quyn u tiên ca lung mà to ra nó.
Lp lung có vài phng thc khi dng, hai trong s các phng thc khi
dng đc đ cp đn di đây:
 public Thread(String threadname)
Cu trúc mt lung vi tên là “threadname”
 public Thread()
Cu trúc mt lung vi tên “Thread, đc ràng buc vi mt s; ly ví d,
Thread-1, Thread-2, v.v…
Chng trình bt đu thc thi lung vi vic gi phng thc start(), mà phng
thc này ph thuc vào lp lung. Phng thc này, ln lt, vin dn phng thc
run(), ni mà phng thc đnh ngha tác v đc thc thi. Phng thc này có th vit
đè lên lp con ca lp lung, hoc vi mt đi tng Runnable.
4. Vòng đi ca Lung

[main, 5 , main]

N
hóm lung mà nó ph thuc vào
Quyn u tiên đc đt bi JVM
Tên ca lung
44

Hình 8.3 Vòng đi ca lung
5. Phm vi ca lung và các phng thc ca lp lung
Mt lung đã đc to mi gn đây là trong phm vi “sinh”. Lung không bt
đu chy ngay lp tc sau khi nó đc to ra. Nó đi phng thc start() ca chính nó
đc gi. Cho đn khi, nó là trong phm vi “sn sàng đ chy”. Lung đi vào phm vi
“đang chay” khi h thng đnh rõ v trí lung trong b vi x lý.
Bn có th s dng phng thc sleep() đ tm thi treo s thc thi ca lung.
Lung tr thành sn sàng sau khi phng thc sleep kt thúc thi gian. Lung Sleeping
không s dng b vi x lý. lung đi vào phm vi “waiting” (đi) khi mt lung đang
chy gi phng thc wait() (đi).
Khi các lung khác liên kt vi các đi tng, gi phng thc notify(), lung đi
vào tr li phm vi “ready” (sn sàng) Lung đi vào phm vi “blocked” (khi) khi nó
đang thc thi các phép toán vào/ra (Input/output). Nó đi vào phm vi “ready” (sn sàng)
khi các phng thc vào/ra nó đang đi cho đn khi đc hoàn thành. Lung đi vào
phm vi “dead” (cht) sau khi phng thc run() đã đc thc thi hoàn toàn, hoc khi
phng thc stop() (dng) ca nó đc gi.
Thêm vào các phng thc đã đc đ cp trên, Lp lung cng có các phng
thc sau:
Phng thc Mc đích
Enumerate(Thread t) Sao chép tt c các lung hin hành vào mng đc ch
đnh t nhóm ca các lung, và các nhóm con ca nó.
getName() Tr v tên ca lung
isAlive() Tr v úng, nu lung là vn còn tn ti (sng)
getPriority() Tr v quyn u tiên ca lung

setName(String name) t tên ca lung là tên mà lung đc truyn nh là
mt tham s.
join() i cho đn khi lung cht.
isDaemon(Boolean on) Kim tra nu lung là lung mt lung him.
resume() ánh du lung nh là lung him hoc lung ngi s
dng ph thuc vào giá tr đc truyn vào.
sleep() Hoãn lung mt khoáng thi gian chính xác.
start() Gi phng thc run() đ bt đu mt lung.
45
Bng 8.1 Các phng thc ca mt lp lung
Bng k hoch Round-robin (bng kin ngh ký tên vòng tròn) liên quan đn các
lung vi cùng quyn u tiên đc chim hu quyn u tiên ca mi lung khác. Chúng
chia nh thi gian mt cách t đng trong theo kiu k hoch xoay vòng này.
Phiên bn mi nht ca Java không h tr các phng thc Thread.suspend() (trì
hoãn), Thread.resume() (phc hi) và Thread.stop() (dng), nh là các phng thc
resume() (phc hi) và suspend() (trì hoãn) đc thiên v s đình tr (deadlock), trong
khi phng thc stop() không an toàn.
6. Thi gian biu lung
Hu ht các chng trình Java làm vic vi nhiu lung. CPU cha đng cho vic
chy chng trình ch mt lung ti mt khong thi gian. Hai lung có cùng quyn u
tiên trong mt chng trình hoàn thành trong mt thi gian CPU. Lp trình viên, hoc
máy o Java, hoc h điu hành chc chn rng CPU đc chia s gia các lung. iu
này đc bit nh là bng thi gian biu lung.
Không có máy o Java nào thc thi rành mch cho bng thi gian biu lung. Mt
s nn Java h tr vic chia nh thi gian.  đây, mi lung nhn mt phn nh ca thi
gian b vi x lý, đc gi là đnh lng. Lung có th thc thi tác v ca chính nó trong
sut khong thi gian đnh lng đy. Sau khong thi gian này đc vt qua, lung
không đc nhn nhiu thi gian đ tip tc thc hin, ngay c nu nó không đc hoàn
thành vic thc hin ca nó. Lung k tip ca lung có quyn u tiên bng nhau này s
ly khong thi gian thay đi ca b vi x lý. Java là ngi lp thi gian biu chia nh tt

c các lung có cùng quyn u tiên cao.
Phng thc setPriority() ly mt s nguyên (integer) nh là mt tham s có th
hiu chnh quyn u tiên ca mt lung. ây là giá tr có phm vi thay đi t 1 đn 10,
mc khác, phng thc đa ra mt ngoi l (by li) đc gi là
IllegalArgumentException (Chp nhn tham s trái lut)
Phng thc yield() (li nhun) đa ra các lung khác mt kh nng đ thc thi.
Phng thc này đc thích hp cho các h thng không chia nh thi gian (non-time-
sliced), ni mà các lung hin thi hoàn thành vic thc hin trc khi các lung có
quyn u tiên ngang nhau k tip tip qun.  đây, bn s gi phng thc yield() ti
nhng khon thi gian riêng bit đ có th tt c các lung có quyn u tiên ngang nhau
chia s thi gian thc thi CPU.
Chng trình 8.2 chng minh quyn u tiên ca lung:
Chng trình 8.2
class PriorityDemo {
Priority t1,t2,t3;
public PriorityDemo(){
t1 = new Priority();
t1.start();
t2 = new Priority();
t2.start();
t3 = new Priority();
t3.start();
}
public static void main(String args[]){
46
new PriorityDemo();
}
class Priority extends Thread implements Runnable{
int sleep;
int prio = 3;

public Priority(){
sleep += 100;
prio++;
setPriority(prio);
}
public void run(){
try{
Thread.sleep(sleep);
System.out.println("Name "+ getName()+" Priority
= "+ getPriority());
}catch(InterruptedException e){
System.out.println(e.getMessage());
}
}
}

}

Kt qu hin th nh hình 8.4

Hình 8.4 Quyn u tiên lung
7. Lung him
Mt chng trình Java b ngt ch sau khi tt c các lung b cht. Có hai kiu
lung trong mt chng trình Java:
 Các lung ngi s dng
 Lung him
Ngi s dng to ra các lung ngi s dng, trong khi các lung đc ch đnh
nh là lung “background” (nn). Lung him cung cp các dch v cho các lung khác.
Máy o Java thc hin tin trình thoát, khi và ch khi lung him vn còn sng. Máy o
47

Java có ít nht mt lung him đc bit đn nh là lung “garbage collection” (thu
lm nhng d liu vô ngha - dn rác). Lung dn rác thc thi ch khi h thng không
có tác v nào. Nó là mt lung có quyn u tiên thp. Lp lung có hai phng thc đ
tha thun vi các lung him:
 public void setDaemon(boolean on)
 public boolean isDaemon()
8. a tuyn vi Applets
Trong khi đa tuyn là rt hu dng trong các chng trình ng dng đc lp, nó
cng đáng đc quan tâm vi các ng dng trên Web. a tuyn đc s dng trên web,
cho ví d, trong các trò chi đa phng tin, các bc nh đy sinh khí, hin th các dòng
ch chy qua li trên biu ng, hin th đng h thi gian nh là mt phn ca trang Web
v.vv… Các chc nng này cu thành các trang web làm quyn r và bt mt.
Chng trình Java da trên Applet thng s dng nhiu hn mt lung. Trong
đa tuyn vi Applet, lp java.applet.Applet là lp con đc to ra bi ngi s dng đnh
ngha applet. T đó, Java không h tr nhiu k tha vi các lp, nó không th thc hin
đc trc tip lp con ca lp lung trong các applet. Tuy nhiên, chúng ta s dng mt
đi tng ca lung ngi s dng đã đnh ngha, mà các lung này, ln lt, dn xut t
lp lung. Mt lung đn gin xut hin s đc thc thi ti giao din (Interface)
Runnable
Chng trình 8.3 ch ra điu này thc thi nh th nào:
Chng trình 8.3
import java.awt.*;
import java.applet.*;
public class Myapplet extends Applet implements Runnable {
int i;
Thread t;
/**
* Myapplet constructor comment.
*/
public void init(){

t = new Thread(this);
t.start();
}
public void paint(Graphics g){
g.drawString(" i = "+i,30,30);
}
public void run(){
for(i = 1;i<=20;i++){
try{
repaint();
Thread.sleep(500);
}catch(InterruptedException e){
System.out.println(e.getMessage());
}
48
}
}
}

Trong chng trình này, chúng ta to ra mt Applet đc gi là Myapplet, và
thc thi giao din Runnable đ cung cp kh nng đa tuyn cho applet. Sau đó, chúng ta
to ra mt th nghim (instance) cho lp lung, vi th nghim applet hin thi nh là
mt tham s đ thit lp (khi dng). Ri thì chúng ta vin dn phng thc start() ca
lung th nghim này. Ln lt, ri s vin dn phng thc run(), mà phng thc này
thc s là đim bt đu cho phng thc này. Chúng ta in s t 1 đn 20 vi thi gian
kéo tr là 500 miligiây gia mi s. Phng thc sleep() đc gi đ hoàn thành thi
gian kéo tr này. ây là mt phng thc tnh đc đnh ngha trong lp lung. Nó cho
phép lung nm yên (ng) trong khon thi gian hn ch.
Xut ra ngoài có dng nh sau:


Hình 8.5 a tuyn vi Applet
9. Nhóm lung
Mt lp nhóm lung (ThreadGroup) nm bt mt nhóm ca các lung. Ly ví d,
mt nhóm lung trong mt trình duyt có th qun lý tt c các lung ph thuc vào mt
đn th applet. Tt c các lung trong máy o Java ph thuc vào các nhóm lung mc
đnh. Mi nhóm lung có mt nhóm ngun cha. Vì th, các nhóm t mt cu trúc dng
cây. Nhóm lung “h thng” là gc ca tt c các nhóm lung. Mt nhóm lung có th là
thành phn ca c các lung, và các nhóm lung.
Hai kiu nhóm lung thit lp (khi dng) là:
 public ThreadGroup(String str)
 đây, “str” là tên ca nhóm lung mi nht đc to ra.
 public ThreadGroup(ThreadGroup tgroup, String str)
 đây, “tgroup” ch ra lung đang chy hin thi nh là lung cha, “str” là tên ca
nhóm lung đang đc to ra.
Mt s các phng thc trong nhóm lung (ThreadGroup) đc cho nh sau:
 public synchronized int activeCount()
49
Tr v s lng các lung kích hot hin hành trong nhóm lung
 public sunchronized int activeGroupCount()
Tr v s lng các nhóm hot đng trong nhóm lung
 public final String getName()
Tr v tên ca nhóm lung
 public final ThreadGroup getParent()
Tr v cha ca nhóm lung
10. S đng b lung
Trong khi đang làm vic vi nhiu lung, nhiu hn mt lung có th mun thâm
nhp cùng bin ti cùng thi đim. Ly ví d, mt lung có th c gng đc d liu, trong
khi lung khác c gng thay đi d liu. Trong trng hp này, d liu có th b sai lc.
Trong nhng trng hp này, bn cn cho phép mt lung hoàn thành trn vn
tác v ca nó (thay đi giá tr), và ri thì cho phép các lung k tip thc thi. Khi hai

hoc nhiu hn các lung cn thâm nhp đn mt tài nguyên đc chia s, bn cn chc
chn rng tài nguyên đó s đc s dng ch bi mt lung ti mt thi đim. Tin trình
này đc gi là “s đng b” (synchronization) đc s dng đ lu tr cho vn đ này,
Java cung cp duy nht, ngôn ng cp cao h tr cho s đng b này. Phng thc “đng
b” (synchronized) báo cho h thng đt mt khóa vòng mt tài nguyên riêng bit.
Mu cht ca s đng b hóa là khái nim “monitor” (s quan sát, giám sát),
cng đc bit nh là mt bng mã “semaphore” (bng mã). Mt “monitor” là mt đi
tng mà đc s dng nh là mt khóa qua li duy nht, hoc “mutex”. Ch mt lung
có th có riêng nó mt s quan sát (monitor) ti mi thi đim đc đa ra. Tt c các
lung khác c gng thâm nhp vào monitor b khóa s b trì hoãn, cho đn khi lung đu
tiên thoát khi monitor. Các lung khác đc báo ch đi monitor. Mt lung mà
monitor ca riêng nó có th thâm nhp tr li cùng monitor.
1. Mã đng b
Tt c các đi tng trong Java đc liên kt vi các monitor (s giám sát) ca
riêng nó.  đng nhp vào monitor ca mt đi tng, lp trình viên s dng t khóa
synchronized (đng b) đ gi mt phng thc hiu chnh (modified). Khi mt lung
đang đc thc thi trong phm vi mt phng thc đng b (synchronized), bt k lung
khác hoc phng thc đng b khác mà c gng gi nó trong cùng th nghim s phi
đi.
Chng trình 8.4 chng minh s làm vic ca t khóa synchronized (s đng b).
 đây, lp “Target” (mc tiêu) có mt phng thc “display()” (hin th) mà phng
thc này ly mt tham s kiu s nguyên (int). S này đc hin th trong phm vi các
cp ký t “< > # s # <>”. Phng thc “Thread.sleep(1000) tm dng lung hin ti sau
khi phng thc “display()” đc gi.
Thit lp (khi dng) ca lip “Source” ly mt tham chiu đn mt đi tng “t”
ca lp “Target”, và mt bin s nguyên (integer).  đây, mt lung mi cng đc to
ra. Lung này gi phng thc run() ca đi tng “t”. Lp chính “Synch” th nghim
lp “Target” nh là “target (mc tiêu), và to ra 3 đi tng ca lp “Source” (ngun).
Cùng đi tng “target” đc truyn cho mi đi tng “Source”. Phng thc “join()”
(gia nhp) làm lung đc gi đi cho đn khi vic gi lung b ngt.

50
Chng trình 8.4

class Target {

/**
* Target constructor comment.
*/
synchronized void display(int num) {
System.out.print("<> "+num);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
System.out.println("Interrupted");
}
System.out.println(" <>");
}
}

class Source implements Runnable{
int number;
Target target;
Thread t;
/**
* Source constructor comment.
*/
public Source(Target targ,int n){
target = targ;
number = n;
t = new Thread(this);

t.start();
}
public void run(){
synchronized(target) {
target.display(number);
}
}
}

class Sync {
/**
* Sync constructor comment.
*/
public static void main(String args[]){
Target target = new Target();
int digit = 10;
Source s1 = new Source(target,digit++);
51
Source s2 = new Source(target,digit++);
Source s3 = new Source(target,digit++);
try{
s1.t.join();
s2.t.join();
s3.t.join();
}catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}


Kt qu hin th nh hình cho di đây:

Hình 8.6 Kt qu hin th ca chng trình 8.4
Trong chng trình trên, có mt “dãy s” đng nhp đc hin th “display()”.
iu này có ngha là vic thâm nhp b hn ch mt lung ti mi thi đim. Nu t khóa
synchronized đt trc b b quên trong phng thc “display()” ca lp “Target”, tt c
lung trên có th cùng lúc gi cùng phng thc, trên cùng đi tng. iu kin này
đc bit đn nh là “loi điu kin” (race condition). Trong trng hp này, vic xut ra
ngoài s đc ch ra nh hình 8.7
52

Hình 8.7 Kt qu hin th ca chng trình 8.7 không có s đng b
2. S dng khi đng b (Synchronized Block)
To ra các phng thc synchronzed (đng b) trong phm vi các lp là mt con
đng d dàng và có hiu qu ca vic thc hin s đng b. Tuy nhiên, điu này không
làm vic trong tt c các trng hp.
Hãy xem mt trng hp ni mà lp trình viên mun s đng b đc xâm nhp
vào các đi tng ca lp mà không đc thit k cho thâm nhp đa tuyn. Tc là, lp
không s dng các phng thc đng b. Hn na, mã ngun là không có giá tr. Vì th
t khoá synchronized không th đc thêm vào các phng thc thích hp trong phm vi
lp.
 đng b thâm nhp mt đi tng ca lp này, tt c chúng gi các phng
thc mà lp này đnh ngha, đc đt bên trong mt khi đng b. Tt c chúng s dng
chung mt câu lnh đng b đc cho nh sau:
synchronized(object)
{
// các câu lnh đng b
}
 đây, “object” (đi tng) là mt tham chiu đn đi tng đc đng b. Du
ngoc móc không cn thit khi ch mt câu lnh đc đng b. Mt khi đng b bo

đm rng nó gi đn mt phng thc (mà là thành phn ca đi tng) xut hin ch sau
khi lung hin hành đã đc tham nhp thành công vào monitor (s quan sát) ca đi
tng.
Chng trình 8.5 ch ra câu lnh đng b s dng nh th nào:
Chng trình 8.5
class Target {

/**
* Target constructor comment.
*/
synchronized void display(int num) {
System.out.print("<> "+num);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
System.out.println("Interrupted");
}
53
System.out.println(" <>");
}
}

class Source implements Runnable{
int number;
Target target;
Thread t;
/**
* Source constructor comment.
*/
public Source(Target targ,int n){

target = targ;
number = n;
t = new Thread(this);
t.start();
}
// đng b gi phng thc display()
public void run(){
synchronized(target) {
target.display(number);
}
}
}

class Synchblock {
/**
* Synchblock constructor comment.
*/
public static void main(String args[]){
Target target = new Target();
int digit = 10;
Source s1 = new Source(target,digit++);
Source s2 = new Source(target,digit++);
Source s3 = new Source(target,digit++);
try{
s1.t.join();
s2.t.join();
s3.t.join();
}catch(InterruptedException e){
System.out.println("Interrupted");
}

}
}
54
 đây, t khóa synchronized không hiu chnh phng thc “display()”. T khóa
này đc s dng trong phng thc run() ca lp “Target” (mc tiêu). Kt qu xut ra
màn hình tng t vi kt qu ch ra  hình s 8.6
3. S không thun li ca các phng thc đng b
Ngi lp trình thng vit các chng trình trên các đn th lung. Tt nhiên
các trng thái này chc chn không li ích cho đa tuyn. Ly ví d, lng không tn dng
vic thc thi ca trình biên dch. Trình biên dch Java t Sun không cha nhiu phng
thc đng b.
Các phng thc đng b không thc thi tt nh là các phng thc không đng
b. Các phng thc này chm hn t ba đn bn ln so vi các phng thc tng ng
không đng b. Trong trng thái ni mà vic thc thi là có gii hn, các phng thc
đng b b ngn nga.
11. K thut “wait-notify” (đi – thông báo)
Lung chia các tác v thành các đn v riêng bit và logic (hp lý). iu này thay
th các trng hp (s kin) chng trình lp. Các lung loi tr “polling” (kim soát
vòng).
Mt vòng lp mà lp li vic mt s điu kin thng thc thi “polling” (kim
soát vòng). Khi điu kin nhn giá tr là True (đúng), các câu lnh phúc đáp đc thc
hin. ây là tin trình thng b phí thi gian ca CPU. Ly ví d, khi mt lung sinh ra
mt s d liu, và các lung khác đang chi phi nó, lung sinh ra phi đi cho đn khi
các lung s dng nó hoàn thành, trc khi phát sinh ra d liu.
 tránh trng hp kim soát vòng, Java bao gm mt thit k tt trong tin
trình k thut truyn thông s dng các phng thc “wait()” (đi), “notify()” (thông
báo) và “notifyAll()” (thông báo ht). Các phng thc này đc thc hin nh là các
các phng thc cui cùng trong lp đi tng (Object), đ mà tt c các lp có th thâm
nhp chúng. Tt c 3 phng thc này có th đc gi ch t trong phm vi mt phng
thc đng b (synchronized).

Các chc nng ca các phng thc “wait()”, “notify()”, và “notifyAll()” là:
 Phng thc wait() nói cho vic gi lung trao cho monitor (s giám sát), và
nhp trng thái “sleep” (ch) cho đn khi mt s lung khác thâm nhp cùng
monitor, và gi phng thc “notify()”.
 Phng thc notify() đánh thc, hoc thông báo cho lung đu tiên mà đã gi
phng thc wait() trên cùng đi tng.
 Phng thc notifyAll() đánh thc, hoc thông báo tt c các lung mà đã
gi phng thc wait() trên cùng đi tng.
 Quyn u tiên cao nht lung chy đu tiên.
Cú pháp ca 3 phng thc này nh sau:
final void wait() throws IOException
final void notify()
final void notifyAll()
55
Các phng thc wait() và notify() cho phép mt đi tng đc chia s đ tm
ngng mt lung, khi đi tng tr thành không còn giá tr cho lung. Chúng cng cho
phép lung tip tc khi thích hp.
Các lung bn thân nó không bao gi kim tra trng thái ca đi tng đã chia s.
Mt đi tng mà điu khin các lung khách (client) ca chính nó theo kiu này
đc bit nh là mt monitor (s giám sát). Trong các thut ng cht ch ca Java, mt
monitor là bt k đi tng nào mà có mt s mã đng b. Các monitor đc s dng
cho các phng thc wait() và notify(). C hai phng thc này phi đc gi trong mã
đng b.
Mt s đim cn nh trong khi s dng phng thc wait():
 Lung đang gi đa vào CPU
 Lung đang gi đa vào khóa
 Lung đang gi đi vào vùng đi ca monitor.
Các đim chính cn nh v phng thc notify()
 Mt lung đa ra ngoài vùng đi ca monitor, và vào trng thái sn sàng.
 Lung mà đã đc thông báo phi thu tr li khóa ca monitor trc khi nó có

th bt đu.
 Phng thc notify() là không chính xác, nh là nó không th ch ra đc
lung mà phi đc thông báo. Trong mt trng thái đã trn ln, lung có th
thay đi trng thái ca monitor trong mt con đng mà không mang li kt
qu tt cho lung đã đc đa thông báo. Trong mt s trng hp này, các
phng thc ca monitor đa ra 2 s đ phòng:
o Trng thái ca monitor s đc kim tra trong mt vòng lp “while”
tt hn là câu lnh if
o Sau khi thay đi trng thái ca monitor, phng thc notifyAll() s
đc s dng, tt hn phng thc notify().
Chng trình 8.6 biu th cho vic s dng các phng thc notify(0 và wait():
Chng trình 8.6
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
/*<applet code = “mouseApplet” width = “100” height = “100”> </applet> */
public class mouseApplet extends Applet implements MouseListener{
boolean click;
int count;
public void init() {
super.init();
add(new clickArea(this)); //doi tuong ve duoc tao ra va them vao
add(new clickArea(this));//doi tuong ve duoc tao ra va them vao
addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {

}
public void mouseEntered(MouseEvent e) {


56
}
public void mouseExited(MouseEvent e) {

}
public void mousePressed(MouseEvent e) {
synchronized (this) {
click = true;
notify();
}
count++; //dem viec click
Thread.currentThread().yield();
click = false;

}
public void mouseReleased(MouseEvent e) {

}
} //kt thúc Applet

class clickArea extends java.awt.Canvas implements Runnable{
mouseApplet myapp;
clickArea(mouseApplet mapp){
this.myapp = mapp;
setSize(40,40);
new Thread(this).start();
}
public void paint(Graphics g){
g.drawString(new Integer(myapp.count).toString(),15,20);


}
public void run(){
while(true){
synchronized (myapp) {
while(!myapp.click){
try{
myapp.wait();
}catch(InterruptedException ie){
}
}
}
repaint(250);
}

}//end run
}

57
Không cn các phng thc wait() và notify(), lung bc v (canvas) không th
bit khi nào cp nhp hin th. Kt qu xut ra ngoài ca chng trình đc đa ra nh
sau:

Hình 8.8 Kt qu sau mi ln kích chut
12. S b tt (Deadlocks)
Mt “deadlock” (s b tt) xy ra khi hai lung có mt ph thuc vòng
quanh trên mt cp đi tng đng b; ly ví d, khi mt lung thâm nhp vào monitor
trên đi tng “ObjA”, và mt lung khác thâm nhp vào monitor trên đi tng “ObjB”.
Nu lung trong “ObjA” c gng gi phng thc đng b trên “ObjB”, mt b tt xy
ra.
Nó khó đ g li mt b tt bi nhng nguyên nhân sau:

 Nó him khi xy ra, khi hai lung chia nh thi gian trong cùng mt con
đng
 Nó có th bao hàm nhiu hn hai lung và hai đi tng đng b
Nu mt chng trình đa tuyn khóa kín thng xuyên, ngay lp tc kim tra li
điu kin b tt.
Chng trình 8.7 to ra điu kin b tt. Lp chính (main) bt đu 2 lung. Mi
lung gi phng thc đng b run(). Khi lung “t1” đánh thc, nó gi phng thc
“synchIt()” ca đi tng deadlock “dlk1”. T đó lung “t2” mt mình giám sát cho
“dlk2”, lung “t1” bt đu đi monitor. Khi lung “t2” đánh thc, nó c gng gi phng
thc “synchIt()” ca đi tng Deadlock “dlk2”. Bây gi, “t2” cng phi đi, bi vì đây
là trng hp tng t vi lung “t1”. T đó, c hai lung đang đi ln nhau, c hai s
đánh thc. ây là điu kin b tt.
Chng trình 8.7
public class Deadlock implements Runnable{
public static void main(String args[]){
Deadlock dlk1= new Deadlock();
Deadlock dlk2 = new Deadlock();
Thread t1 = new Thread(dlk1);
Thread t2 = new Thread(dlk2);

dlk1.grabIt = dlk1;
dlk2.grabIt = dlk2;
58
t1.start();
t2.start();
System.out.println("Started");
try{
t1.join();
t2.join();
}catch(InterruptedException e){

System.out.println("error occured");
}
System.exit(0);
}
Deadlock grabIt;
public synchronized void run() {
try{
Thread.sleep(1500);
}catch(InterruptedException e){
System.out.println("error occured");
}
grabIt.syncIt();
}
public synchronized void syncIt() {
try{
Thread.sleep(1500);
System.out.println("Sync");

}catch(InterruptedException e){
System.out.println("error occured");
}
System.out.println("In the syncIt() method");
}
}

Kt qu ca chng trình này đc hin th nh sau:

Hình 8.9 S b tt

59

13. Thu dn “rác” (Garbage collection)
Thu dn “rác” (Garbage collection) ci to hoc làm trng b nh đã đnh v cho
các đi tng mà các đi tng này không s dng trong thi gian dài. Trong ngôn ng
lp trình hng đi tng khác nh C++, lp trình viên phi làm cho b nh trng mà đã
không đc yêu cu trong thi gian dài. Tình trng không hot đng đ b nh trng có
th là kt qu trong mt s vn đ. Java t đng tin trình thu dn rác đ cung cp gii
pháp duy nht cho vn đ này. Mt đi tng tr nên thích hp cho s dn rác nu không
có tham chiu đn nó, hoc nu nó đã đng ký rng.
S dn rác thc thi nh là mt lung riêng bit có quyn u tiên thp. Bn có th
vin dn mt phng thc gc() ca th nghim đ vin dn s dn rác. Tuy nhiên, bn
không th d đoán hoc bo đm rng s dn rác s thc thi mt cách trn vn sau đó.
S dng câu ln sau đ tt đi s dn rác trong ng dng:
Java –noasyncgc ….
Nu chúng ta tt đi s dn rác, chng trình hu nh chc chn rng b treo do
bi vic đó.
1. Phng thc finalize() (hoàn thành)
Java cung cp mt con đng đ làm sch mt tin trình trc khi điu khin tr
li h điu hành. iu này tng t nh phng thc phân hy ca C++
Phng thc finalize(), nu hin din, s đc thc thi trên mi đi tng, trc
khi s dn rác.
Câu lnh ca phng thc finalize() nh sau:
protected void finalize() throws Throwable
Tham chiu không phi là s dn rác; ch các đi tng mi đc dn rác
Ly th nghim:
Object a = new Object();
Object b = a;
a = null;
 đây, nó s sai khi nói rng “b” là mt đi tng. Nó ch là mt đi tng tham
chiu. Hn na, trong đon mã trích trên mc dù “a’ đc đt là rng, nó không th đc
dn rác, bi vì nó vn còn có mt tham chiu (b) đn nó. Vì th “a” vn còn vi đn

đc, tht vy, nó vn còn có phn vi s dng trong phm vi chng trình.  đây, nó s
không đc dn rác.
Tuy nhiên, trong ví d cho di đây, gi đnh rng không có tham chiu đn “a”
tn ti, đi tng “a” tr nên thích hp cho garbage collection.
Object a = new Object();



a = null;
Mt ví d khác:
Object m = new Object();
Object m = null;
60
i tng đc to ra trong s bt đu có hiu lc cho garbage collection
Object m = new Object();
M = new Object();
Bây gi, đi tng cn nguyên có hiu lc cho garbage collection, và mt đi
tng mi tham chiu bi “m” đang tn ti.
Bn có th chy phng thc garbage collection, nhng không có ban đm rng
nó s xy ra.
Chng trình 8.8 đin hình cho garbage collection.
Chng trình 8.8
class GCDemo
{
public static void main(String args[])
{
int i;
long a; ,
Runtime r=Runtime.getRuntimeO;
Long valuesD =new Long[200];

System. out. print In ("Amount of free memory is" +
r.freeMemoryO);
r.gcO;
System.out.println("Amount of free memory after garbage
collection is " + r.freeMemoryO);
for (a=IOOOO.i=O;i<200;a++.i++)
{
values[i] =new Long(a);
}
System.out.println("Amount of free memory after creating the array
" + r.freeMemoryO);
for (i=O;i<200;i++)
{
values[i] =null;
}
System.out.println("Arnount of free memory after garbage collection is
" + r.freeMemoryO);
}

Chúng ta khai mt mng gm 200 phn t, trong đó kiu d liu là kiu Long.
Trc khi mng đc to ra, chúng ta phi xác đnh rõ s lng b nh trng, và hin th
nó. Ri thì chúng ta vin dn phng thc gc() ca th nghim Runtime (thi gian thc
thi) hin thi. iu này có th hoc không th thc thi garbage collection. Ri thì chúng
ta to ra mng, và đang ký giá tr cho các phn t ca mng. iu này s gim bt s
lng b nh trng.  làm các mng phn t thích hp cho garbage collection, chúng ta
đt chúng rng. Cui cùng, chúng ta s dng phng thc gc() đ vin dn garbage
collection ln na.
Kt qu xut ra màn hình ca chng trình trên nh sau:
61


Hình 8.10 Garbage collection
Tng kt
 Mt lung là đn v nh nht ca đon mã thc thi đc mà mt tác v riêng
bit.
 a tuyn gi cho thi gian ri là nh nht. iu này cho phép bn vit các
chng trình có kh nng s dng ti đa CPU.
 Lung bt đu thc thi sau khi phng thc start() đc gi
 Lp trình viên, máy o Java, hoc h điu hành bo đm rng CPU đc chia
s gia các lung.
 Có hai loi lung trong mt chng trình Java:
o Lung ngi dùng
o Lung him.
 Mt nhóm lung là mt lp mà nm bt mt nhóm các lung.
 ng b cho phép ch mt lung thâm nhp mt tài nguyên đc chia s ti
mt thi đim.
  tránh kim soát vòng, Java bao gm mt thit k tt trong tin trình k
thut truyn thông s dng các phng thc “wait()” (đi), “notify()” (thông
báo) và “notifyAll()” (thông báo ht).
 Mt “b tt” xy ra khi hai lung có mt ph thuc xoay vòng trên mt phn
ca các đi tng đng b
 Garbage collection là mt tin trình nh đó b nh đc đnh v đ các đi
tng mà không s dng trong thi gian dài, có th ci to hoc làm rãnh b
nh.
Kim tra li s hiu bit ca bn
1. Mt ng dng có th cha đng nhiu lung úng/Sai
2. Các lung con đc to ra t lung chính úng/Sai
3. Mi lung trong mt chng trình Java đc đng ký mt quyn u tiên mà máy
o Java có th thay đi. úng/Sai
62
4. Phng thc____________ có th tm thi ngng vic thc thi lung

5. Mc đnh, mt lung có mt quyn u tiên ________ mt hng s ca _______
6. _________ lung đc dùng cho các lung “nn”, cung cp dch v cho lung
khác.
7. Trong lung đng b, mt __________ là mt đi tng mà đc s dng nh là
mt khóa riêng bit ln nhau.
8. ___________ thng thc thi bi mt vòng lp mà đc s dng đ lp li vic
kim tra mt s điu kin.

Bài tp:
1. Vit mt chng trình mà hin th mt s đm lùi tng giây cho đn không, nh
hình sau:



Ban đu, s 300 s đc hin th. Giá tr s đc gim dn cho đn 1 đn khi
ngoài giá tr 0. Giá tr s đc tr li 300 mt ln na gim đn tr thành 0.
63
2. Vit mt chng trình mà hin th nh hình di đây:



To 3 lung và mt lung chính trong “main”. Thc thi mi lung nh mt
chng trình thc thi. Khi chng trình kt thúc, các câu lnh thoát cho mi lung s
đc hin th. S dng k thut nm bt li.




×