|
|
|
|
Fils (Threads). El procés
continu. |
|
|
|
|
|
Programació multitasca: |
|
|
|
|
|
|
Els sistemes operatius
actuals són tots multitasca , és a dir, poden executar
diferents feines simultànies, i també tenen la capacitat de
gestionar programes dissenyats per a llançar diferents fils
(seguits de tasques, "threads") considerablement independents
els uns dels altres.
Gairebé tots els programes que pots trobar actualment en el mercat
són multifil. Estàs acostumats a que un programa
pugui fer diverses coses a la vegada i segur que t'irrita, tanmateix,
que un procés que no respon et bloquegi l'aplicació i, fins
i tot et pengi l'ordinador. Som consumidors de programes multifil
i ens hem de convertir en dissenyadors de programació concurrent,
com a mínim si volem fer projectes de dimensions mitjanes que transmetin
a l'usuari sensació d'agilitat i solidesa.
Java
està ben preparat per a la programació en fils. Disposa
d'una classe específica, java.lang.Thread,
i una interfície, java.lang.Runnable,
que et permetran aplicar fils a qualsevol lloc que calgui. No tot
són bones notícies, però: com d'altres aspectes de
la programació avançada, codificar amb fils no és
pas cap tasca intuïtiva. Els fils són objectes delicats
i complicats perquè poden tenir preferències d'execució
diferents, poden escoltar-se els uns als altres, poden agrupar-se, fer
exclusivament de servidors d'altres fils i tantes altres característiques
que el seu aprenentatge podria ocupar tot aquest curs
|
|
|
|
|
|
El procés continu: |
|
|
|
|
|
|
El procés continu
del Joc de la Vida
ha de ser un Thread (fil) d'aquests:ha
de funcionar ell sol amb independència de si premem un botó
o fem qualsevol altra acció. Naturalment, l'acció (esdeveniment!)
de prémer el botó "Procés continu: aturar/engegar"
ha de fer alguna cosa sobre aquest Thread (fil),
però pas cap altra cosa! |
|
|
|
|
|
La classe java.lang.Thread,
que és la que representa un fil, servirà per a aquesta
finalitat. La classe conté, entre d'altres, quatre mètodes
que són els importants ara: |
|
|
|
|
|
- public void start (): Fa que
el Thread (fil) comenci a executar-se:
la Màquina
Virtual de Java, aleshores, crida al mètode run()
d'aquest Thread.
- public void run (): És
el mètode cridat en començar l'execució del Thread
(fil). Aquest mètode ha de contenir tot allò que
vulguis que faci aquest Thread. El mètode
run() no s'ha de cridar mai directament: per
engegar un Thread cal cridar el mètode
start() d'aquest Thread.
- public static void sleep (long millisegons):
Per adormir el Thread la quantitat
de mil·lisegons desitjada. L'ús principal (que és
el que en faràs aquí) és el de controlar la velocitat
d'execució dels bucles while o for.
- public final void setPriority(int prioritat):
Per determinar la prioritat d'execució d'aquest Thread
davant d'altres Threads. El paràmetre
int prioritat ha de ser un dels valors static
int MAX_PRIORITY, static int MIN_PRIORITY
o static int NORM_PRIORITY.
|
|
|
|
|
 |
Ja pots començar: al projecte
JocDeLaVida hi crees la nova classe ProcesContinu,
filla de la classe Thread: |
|
|
|
|
 |
/**
* La classe ProcesContinu representa el procés que resulta
de
* l'encadenament sense solució de continuitat de successius
* estats del món del "Joc de la Vida".
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class ProcesContinu extends Thread {
/**
* La Finestra en la qual s'esdevé
aquest ProcésContinu.
*/
protected Finestra finestra;
/**
* Mètode constructor per a objectes
de la classe
* ProcesContinu.
* @param finestra la Finestra en la qual
s'esdevé aquest
* ProcésContinu.
*/
public ProcesContinu(Finestra finestra)
{ // constructor
this.finestra=finestra;
setPriority(Thread.MIN_PRIORITY);
}
}
|
|
|
|
|
|
|
Observa que, per començar,
al fil ProcesContinu li dónes prioritat
mínima, per tal que no empipi encara... |
|
|
|
|
|
Ara cal que la classe Finestra
construeixi efectivament el fil ProcesContinu
i el posi en marxa. A la classe Finestra has d'afegir-li
aquest codi: |
|
|
|
|
 |
import
javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/**
* La classe Finestra és la classe arrel de l'aplicació
del Joc
* de la Vida.
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Finestra extends JFrame {
/**
* L'objecte Mon en el qual viuen i
moren els éssers.
*/
protected Mon mon;
/**
* L'objecte MonVisible que fa visibles
els éssers
* del món.
*/
protected MonVisible monVisible;
/**
* Mètode getter per a la variable
mon
* @return el Mon d'aquesta finestra
*/
public Mon getMon () {
return mon;
}
/**
* Mètode getter per a la variable
monVisible
* @return el MonVisible d'aquesta
finestra
*/
public MonVisible getMonVisible () {
return monVisible;
}
/**
* Botó "Pas a pas"
*/
private JButton botoPasAPas;
/**
* El procés continu
*/
private ProcesContinu procesContinu;
/**
* Botó pel comanament del procés
continu
*/
private JButton botoProcesContinu;
/**
* Etiquetes alternatives pel botó
d'engegar i parar el
* procés continu
*/
private String[] etiquetes={"Engegar
procés continu",
"Parar
procés continu"};
/**
* Estat d'activitat del procés continu.
*/
boolean esProcesActiu=false;
/**
* Mètode constructor per a objectes
de la classe Finestra.
*/
public Finestra () { // constructor
setConfiguracio();
setControls();
mon=new Mon();
procesContinu=new
ProcesContinu(this);
procesContinu.start();
inicia();
}
<etc.>
|
|
|
|
|
|
|
Ara has de fer que
el botó "Engegar/parar procés continu" faci
el que ha de fer: simplement establir la prioritat del ProcesContinu.
Al mètode setControls() de la classe Finestra
afegeix-li aquest codi: |
|
|
|
|
 |
<codi anterior>
// Col·locació del botó
"Procés continu"
botoProcesContinu=new JButton(); // Creem el botó
afegeixBoto(botoProcesContinu,panelBotons,etiquetes[0],
new
ActionListener() {
public
void actionPerformed(ActionEvent evt) {
esProcesActiu=!esProcesActiu;
botoPasAPas.setEnabled(!esProcesActiu);
if (esProcesActiu) {
botoProcesContinu.setText(etiquetes[1]);
procesContinu.setPriority(
Thread.MAX_PRIORITY);
}
else {
botoProcesContinu.setText(etiquetes[0]);
procesContinu.setPriority(
Thread.MIN_PRIORITY);
}
}
});
<etc.> |
|
|
|
|
|
|
Ja eta ben a prop
del final! Només cal escriure el mètode run()
de la classe ProcésContinu:, però,
abans, et proposem un exercici: |
|
|
|
|
 |
Exercici: per què no
funciona? |
|
|
|
|
|
|
Compila el projecte
i crea un objecte Finestra. Tens la finestra de
l'aplicació davant teu: ara prem el botó "Engegar/parar
procés continu". Uiiiiiii! Per què Java
se t'enfada tant i tant? |
|
|
|
|
|
El final del projecte... |
|
|
|
|
|
|
Bé, tornem
al mètode run(): has de tancar tota la
seva activitat en un bucle infinit: la clàusula adequada és |
|
|
|
|
|
while (true) {
<...codi...>
}
|
|
|
|
|
|
|
i com que el botó
"Engegar/parar procés continu" canvia la prioritat
d'aquest Thread, faràs servir això
per distingir si el ProcesContinu ha de fer coses
o no: |
|
|
|
|
|
while (true) {
if
(getPriority()>Thread.MIN_PRIORITY) {
<...accions
a fer...>
}
}
|
|
|
|
|
|
|
Les accions a fer
són simplement que el mon faci un pas()
i que el monVisible es repinti. Per tal de controlar
la velocitat dels esdeveniments, després d'això cal posar
a dormir el procesContinu uns quants mil·lisegons:
100 ja estarà bé. El mètode run()
de la classe ProcesContinu queda així: |
|
|
|
|
|
<codi anterior>
/**
* Mètode run() per a objectes
de la classe
* ProcesContinu.
*/
public void run () {
Mon mon=finestra.getMon();
MonVisible monVisible=finestra.getMonVisible();
while(true)
{
if
(getPriority()>Thread.MIN_PRIORITY) {
mon.pas();
monVisible.repaint();
try
{
sleep(100);
}
catch (In | |