miércoles, 24 de septiembre de 2014

Un ejemplo de hilos no sincronizados (Consumidor y Productor)

He aqui lo último en trabajos sencillos pero efectivos. Un problema de productores y consumidores con hilos en java. 2 productores, 3 consumidores, todo el drama.

package ejemplo;
public class DatosCompartidos {
public String dato;
public String getDato(){
return dato;
}
public void newDato(String dato){
this.dato=dato;
}
}

El productor
package ejemplo;
public class Productor extends Thread{
public DatosCompartidos datos;
public String nombre;
Productor(DatosCompartidos dc, String nmbr){
datos=dc;
nombre=nmbr;
}
public void run(){
Integer i=0;
while(true){
i++;
datos.newDato(i.toString());
System.out.println(nombre+" produce "+i);
}
}
}
view raw Productor.java hosted with ❤ by GitHub

El consumidor
package ejemplo;
public class Consumidor extends Thread{
public DatosCompartidos datos;
public String nombre;
Consumidor(DatosCompartidos dc, String nmbr){
datos=dc;
nombre=nmbr;
}
public void run(){
while(true){
System.out.println(nombre+" consume "+datos.getDato());
}
}
}
view raw Consumidor.java hosted with ❤ by GitHub

Y finalmente, el main. Aquí llamo a 2 productores y 3 consumidores.
package ejemplo;
public class ProducerConsumerSinSincro {
public static void main(String[] args){
DatosCompartidos datos=new DatosCompartidos();
Productor p1=new Productor(datos, "p1");
Productor p2=new Productor(datos, "p2");
Consumidor c1=new Consumidor(datos, "c1");
Consumidor c2=new Consumidor(datos, "c2");
Consumidor c3=new Consumidor(datos, "c3");
p1.start();
p2.start();
c1.start();
c2.start();
c3.start();
}
}


Como pueden ver, los hilos no están sincronizados de ninguna manera. Así que es divertido ver como se pelean por los recursos (literalmente, los recursos).

domingo, 21 de septiembre de 2014

La verguenza termina

Este es el cronometro terminado, del que no me averguenzo taaanto.

Primero les paso mi clase lógica, donde manejo el incremento del tiempo segun el estado del thread. Oh si, es un thread.

package cronometro;
public class Logica2 implements Runnable{
Vista2 vis;
public void run(){
Tiempo time=new Tiempo();
while(true){
int msec=time.getMilisec();
int sec=time.getSegundo();
int min=time.getMinuto();
int hora=time.getHora();
try{
Thread.sleep(1000); //Lo duermo 1000 milisegundos, lo que equivale a 1 segundo
}
catch(InterruptedException e){
}
// msec++;
// if(msec>=100){
// sec++;
// msec=0;
// }
sec++;
if(sec>=60){
min++;
sec=0;
}
if(min>=60){
hora++;
min=0;
}
if(hora>=24){
hora=0;
}
if(vis.getAction())
time=new Tiempo();
if(vis.getEstado()){
time.setHora(hora);
time.setMilisec(msec);
time.setMinuto(min);
time.setSegundo(sec);
vis.Acomodar(time); //es el método de la vista que acomoda todo de manera visualmente agradable
}
}
}
public Logica2(Vista2 vista){
vis=vista;
}
}
view raw Logica2.java hosted with ❤ by GitHub

Ahora esta es mi clase Tiempo, la cual contiene todos los datos de, pues, el tiempo.

package cronometro;
public class Tiempo {
private Integer hora;
private Integer minuto;
private Integer segundo;
private Integer milisec;
public Tiempo(){
hora=0;
minuto=0;
segundo=0;
milisec=0;
}
public void setHora(int hora){
this.hora=hora;
}
public void setMinuto(int minuto){
this.minuto=minuto;
}
public void setSegundo(int segundo){
this.segundo=segundo;
}
public void setMilisec(int milisec){
this.milisec=milisec;
}
public Integer getHora(){
return hora;
}
public Integer getMinuto(){
return minuto;
}
public Integer getSegundo(){
return segundo;
}
public Integer getMilisec(){
return milisec;
}
}
view raw Tiempo.java hosted with ❤ by GitHub

Ahora finalmente, mi clase Vista y la interfaz que implementa. El metodo que usa la vista para acomodar todo es el que recibe de la interfaz, y su unico parámetro es un objeto de Tiempo, que contiene todo lo que necesita para acomodar los números.

package cronometro;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Vista2 extends JFrame implements Interfaz2{
JPanel p1, p2, p3;
JLabel hr, min, sec, msec, dot1, dot2;
JButton start, restart, stop, resume;
private boolean state=false;
private boolean action=false;
public Vista2(){
super("Cronometro");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(50, 50, 480, 300);
p1=new JPanel(new GridLayout(1,5));
p3=new JPanel();
hr=new JLabel("00"); min=new JLabel("00"); sec=new JLabel("00"); msec=new JLabel("00");
dot1=new JLabel(":"); dot2=new JLabel(":");
hr.setFont(new Font("Arial", Font.BOLD, 70));
min.setFont(new Font("Arial", Font.BOLD, 70));
sec.setFont(new Font("Arial", Font.BOLD, 70));
dot1.setFont(new Font("Arial", Font.BOLD, 70));
dot1.setBounds(140,60,100,100);
dot2.setFont(new Font("Arial", Font.BOLD, 70));
dot2.setBounds(280,60,100,100);
p1.add(hr);
add(dot1);
p1.add(min);
add(dot2);
p1.add(sec);
msec.setBounds(420, 85,100,100);
add(msec);
this.add(p1, BorderLayout.CENTER);
p3.setPreferredSize(new Dimension(44,44));
this.add(p3, BorderLayout.WEST);
p2=new JPanel(new FlowLayout());
start=new JButton("Iniciar"); start.setPreferredSize(new Dimension(100,20));
restart=new JButton("Reiniciar"); restart.setPreferredSize(new Dimension(100, 20));
stop=new JButton("Detener"); stop.setPreferredSize(new Dimension(100, 20));
resume=new JButton("Continuar"); resume.setPreferredSize(new Dimension(100, 20));
p2.add(start); p2.add(restart);
p2.add(stop); p2.add(resume);
this.add(p2, BorderLayout.SOUTH);
start.setEnabled(true);
stop.setEnabled(false);
restart.setEnabled(false);
resume.setEnabled(false);
this.setVisible(true);
start.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
state=true;
start.setEnabled(false);
stop.setEnabled(true);
restart.setEnabled(false);
resume.setEnabled(false);
}
});
stop.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
state=false;
stop.setEnabled(false);
restart.setEnabled(true);
resume.setEnabled(true);
}
});
restart.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
hr.setText("00");
min.setText("00");
sec.setText("00");
msec.setText("00");
restart.setEnabled(false);
start.setEnabled(true);
resume.setEnabled(false);
action=true;
}
});
resume.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
state=true;
stop.setEnabled(true);
resume.setEnabled(false);
restart.setEnabled(false);
}
});
}
public boolean getEstado(){
return state;
}
public boolean getAction(){
return action;
}
public void Acomodar(Tiempo time){
//Estetica
if(time.getHora()<10)
hr.setText("0"+time.getHora().toString());
else
hr.setText(time.getHora().toString());
if(time.getMilisec()<10)
msec.setText("0"+time.getMilisec().toString());
else
msec.setText(time.getMilisec().toString());
if(time.getMinuto()<10)
min.setText("0"+time.getMinuto().toString());
else
min.setText(time.getMinuto().toString());
if(time.getSegundo()<10)
sec.setText("0"+time.getSegundo().toString());
else
sec.setText(time.getSegundo().toString());
action=false;
}
}
view raw Vista2.java hosted with ❤ by GitHub

package cronometro;
public interface Interfaz2 {
public void Acomodar(Tiempo time);
}
view raw Interfaz2.java hosted with ❤ by GitHub

La clase main simplemente crea el objeto de Vista2 y arranca el thread. No hace nada más.

package cronometro;
public class Test {
public static void main(String[] args){
//Vista vis=new Vista();
//(new Thread(new Logica(vis))).start();
Vista2 vis=new Vista2();
(new Thread(new Logica2(vis))).start();
}
}
view raw Test.java hosted with ❤ by GitHub


Y así declaro terminada mi tortura :)

domingo, 14 de septiembre de 2014

Primer fail

 He aqui mi primer intento fallido de hacer un cronometro. Esta es mi clase lógica, que es también un hilo que llamo desde el main. Actualmente tengo una mejor versión y me averguenzo de ella, pero todo tiene su humilde origen, ¿no es cierto?

package cronometro;
public class Logica implements Runnable{
private Integer msec, secs, mins, hrs;
private Vista vis;
public Logica(Vista vis){
this.vis=vis;
msec=0;
secs=0;
mins=0;
hrs=0;
}
public void run(){
while(true){
int wea=vis.state;
int cos=vis.accion;
if(cos==1){
msec=0;
secs=0;
mins=0;
hrs=0;
vis.hr.setText("00");
vis.min.setText("00");
vis.sec.setText("00");
vis.msec.setText("00");
vis.accion=0;
}
if(wea==1){
try{
Thread.sleep(10);
}
catch(InterruptedException e){
}
msec++;
if(msec==100){
msec=0;
secs++;
}
if(secs==60){
secs=0;
mins++;
if(vis.dot1.isVisible())
vis.dot1.setVisible(false);
else
vis.dot1.setVisible(true);
}
if(mins==60){
mins=0;
hrs++;
}
if(msec<10)
vis.msec.setText("0"+msec.toString());
else
vis.msec.setText(msec.toString());
if(secs<10)
vis.sec.setText("0"+secs.toString());
else
vis.sec.setText(secs.toString());
if(mins<10)
vis.min.setText("0"+mins.toString());
else
vis.min.setText(mins.toString());
if(hrs<10)
vis.hr.setText("0"+hrs.toString());
else
vis.hr.setText(hrs.toString());
}
}
}
}
view raw Logica.java hosted with ❤ by GitHub



Y esta es la interfaz gráfica, que por desgracia interactua demasiado con la clase lógica.


package cronometro;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Vista extends JFrame implements ActionListener{
JPanel p1, p2, p3;
JLabel hr, min, sec, msec, dot1, dot2;
JButton start, restart, stop, resume;
Integer state=0, accion=0;
public Vista(){
super("Cronometro");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(50, 50, 480, 300);
p1=new JPanel(new GridLayout(1,5));
p3=new JPanel();
hr=new JLabel("00"); min=new JLabel("00"); sec=new JLabel("00"); msec=new JLabel("00");
dot1=new JLabel(":"); dot2=new JLabel(":");
hr.setFont(new Font("Arial", Font.BOLD, 70));
min.setFont(new Font("Arial", Font.BOLD, 70));
sec.setFont(new Font("Arial", Font.BOLD, 70));
dot1.setFont(new Font("Arial", Font.BOLD, 70));
dot1.setBounds(140,60,100,100);
dot2.setFont(new Font("Arial", Font.BOLD, 70));
dot2.setBounds(280,60,100,100);
p1.add(hr);
add(dot1);
p1.add(min);
add(dot2);
p1.add(sec);
msec.setBounds(420, 85,100,100);
add(msec);
this.add(p1, BorderLayout.CENTER);
p3.setPreferredSize(new Dimension(44,44));
this.add(p3, BorderLayout.WEST);
p2=new JPanel(new FlowLayout());
start=new JButton("Iniciar"); start.setPreferredSize(new Dimension(100,20));
start.addActionListener(this);
restart=new JButton("Reiniciar"); restart.setPreferredSize(new Dimension(100, 20));
restart.addActionListener(this);
stop=new JButton("Detener"); stop.setPreferredSize(new Dimension(100, 20));
stop.addActionListener(this);
resume=new JButton("Continuar"); resume.setPreferredSize(new Dimension(100, 20));
resume.addActionListener(this);
p2.add(start); p2.add(restart);
p2.add(stop); p2.add(resume);
this.add(p2, BorderLayout.SOUTH);
start.setVisible(true);
stop.setVisible(false);
restart.setVisible(false);
resume.setVisible(false);
this.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == start){
state=1;
start.setVisible(false);
stop.setVisible(true);
restart.setVisible(true);
}
if(e.getSource() == stop){
state=0;
stop.setVisible(false);
resume.setVisible(true);
}
if(e.getSource() == restart){
accion=1;
}
if(e.getSource() == resume){
state=1;
resume.setVisible(false);
stop.setVisible(true);
}
}
}
view raw Vista.java hosted with ❤ by GitHub