Listado completo de tutoriales

102 - Hilos en Java - método synchronized


Los métodos sincronizados en Java solo pueden tener un hilo ejecutándose dentro de ellos al mismo tiempo.

Son necesarios cuando un método accede a un recurso que puede ser consumido por un único proceso.

Para evitar que un algoritmos sea ejecutado por más de un hilo en forma simultanea, Java nos permite definir un método con el modificador: synchronized.

Cuando un método se lo define synchronized luego solo un hilo puede estar ejecutándolo en un mismo momento.

Problema:

Confeccionar un programa que imprima la cantidad de archivos de texto de un directorio que contienen una determinada palabra. Efectuar la búsqueda dentro de un hilo.

Lanzar la búsqueda de dos palabras en dos hilos separados.



import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class BuscarPalabra implements Runnable {
    private String palabra;
    private Thread hilo;
    private int cant;

    public BuscarPalabra(String palabra) {
        this.palabra = palabra;
        hilo = new Thread(this);
        hilo.start();
        while (hilo.isAlive())
            ;
        System.out.println("La palabra " + palabra + " se encuentra contenida en " + 
                            cant + " archivos");
    }

    @Override
    public void run() {
        File ar = new File("C:\\documentos\\");
        String[] directorio = ar.list();
        for (String arch : directorio) {
            if (tiene(arch))
                cant++;
        }
    }

    private synchronized boolean tiene(String archivo) {
        boolean existe = false;
        try {
            FileReader fr = new FileReader("c:\\documentos\\" + archivo);
            BufferedReader br = new BufferedReader(fr);
            String linea = br.readLine();
            while (linea != null) {
                if (linea.indexOf(palabra) != -1)
                    existe = true;
                linea = br.readLine();
            }
            br.close();
            fr.close();
        } catch (IOException e) {
            System.out.println(e.toString());
        }
        return existe;
    }

    public static void main(String[] ar) {
        new BuscarPalabra("rojo");
        new BuscarPalabra("verde");

    }

}

La clase 'BuscarPalabra' define como atributos la palabra a buscar, un hilo y el contador:

public class BuscarPalabra implements Runnable {
    private String palabra;
    private Thread hilo;
    private int cant;

En el constructor recibimos la palabra a buscar, creamos el hilo y mientras el mismo no finalice no se procede a mostrar el contador de palabras:

    public BuscarPalabra(String palabra) {
        this.palabra = palabra;
        hilo = new Thread(this);
        hilo.start();
        while (hilo.isAlive())
            ;
        System.out.println("La palabra " + palabra + " se encuentra contenida en " + 
                            cant + " archivos");
    }

En el método run que se inicia al llamar al método 'start' del hilo procedemos a obtener todos los archivos del directorio a procesar y llamamos al metodo 'tiene' para cada uno de los archivos de texto:

    @Override
    public void run() {
        File ar = new File("C:\\documentos\\");
        String[] directorio = ar.list();
        for (String arch : directorio) {
            if (tiene(arch))
                cant++;
        }
    }

El método 'tiene' es el método sincronizado, el cual evita que dos hilos puedan en forma simultánea acceder al sistema de archivos.

Abrimos, leemos el archivo de texto y buscamos en cada línea si tiene la palabra:

    private synchronized boolean tiene(String archivo) {
        boolean existe = false;
        try {
            FileReader fr = new FileReader("c:\\documentos\\" + archivo);
            BufferedReader br = new BufferedReader(fr);
            String linea = br.readLine();
            while (linea != null) {
                if (linea.indexOf(palabra) != -1)
                    existe = true;
                linea = br.readLine();
            }
            br.close();
            fr.close();
        } catch (IOException e) {
            System.out.println(e.toString());
        }
        return existe;

    }

En la main creamos dos objetos de la clase 'BuscarPalabra':

    public static void main(String[] ar) {
        new BuscarPalabra("rojo");
        new BuscarPalabra("verde");

    }

Sincronización a nivel de bloques.

Una variante de la sincronización de métodos es definir la sincronización a nivel de bloque, es decir que no afecte a todo el método. La sintaxis luego queda:

    private boolean tiene(String archivo) {
        boolean existe = false;
        synchronized (this) {
            try {
                FileReader fr = new FileReader("c:\\documentos\\" + archivo);
                BufferedReader br = new BufferedReader(fr);
                String linea = br.readLine();
                while (linea != null) {
                    if (linea.indexOf(palabra) != -1)
                        existe = true;
                    linea = br.readLine();
                }
                br.close();
                fr.close();
            } catch (IOException e) {
                System.out.println(e.toString());
            }
        }
        return existe;
    }

Retornar