Java: Comment implémenter le Multi-Threading dans un algorithme récursif de recherche de taille de dossier?


Donc, j'ai déjà développé une version à thread unique du finder de taille de dossier, mais pour le rendre plus intéressant, je voulais améliorer sa vitesse et, espérons-le, développer ma compréhension des processus multi-threads. Cependant, après ~ 30 révisions il semblait toujours y avoir un problème, si c'était:
- Que le thread principal a imprimé le résultat avant que tous les threads aient été faits
- Le type long débordait alors qu'il n'aurait pas dû (doubles comptes possibles peut-être)
- Le multi-thread la version prend plus de temps que la version à thread unique

Je suis perdu, je ne sais pas si un tel problème ne convient tout simplement pas au multi-threading ou si je m'y prends mal. J'ai placé ma révision la plus "réussie" ci-dessous.

Je me rends compte qu'il commence techniquement puis rejoint immédiatement le thread de travail, ce qui le rend presque pire que le simple foulage. Cependant, c'est le seul moyen d'obtenir le thread principal pour afficher le résultat correct.

Donc mon principal le problème consiste à faire en sorte que le thread de travail ne se joigne qu'à la fin, ce qui lui permet d'explorer tous les sous-dossiers en parallèle, puis de se joindre au thread principal pour afficher le résultat correct.

package sizeBrowserCode;

import java.io.File;
import java.io.FileWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class Main {
static long lengthy;
static Thread worker;
static long sum;

private static long getLength() {
    return Main.lengthy;
}

private static void setLength(long var) {
    Main.lengthy=var;
}

private static long getFolderSize(File folder) {
    long length=0;
    File[] files = folder.listFiles();

    int count = files.length;

    for (int i = 0; i < count; i++) {
        if (files[i].isFile()) {
            length += files[i].length();
        }
        else {
            length += getFolderSize(files[i],true);
        }
    }
    System.out.println(folder+" // "+length);

    return length;
}

private static long getFolderSize(File folder,boolean multiThreaded) {
    if(multiThreaded) {
        long length;
        worker=new Thread(new Runnable() {
             public void run() {

                setLength(getFolderSize(folder));
                 }
                });
            worker.start();
            try {
                worker.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            length=getLength();
        return length;

    }else {
        return getFolderSize(folder);
    }
}


public static String convert_Bytes(long bytes,String prefered_Unit) {
    prefered_Unit=prefered_Unit.toLowerCase().trim();
    switch (prefered_Unit) {
    case "b": return (bytes+" Bytes");
    case "kb": return (bytes/1024+" Kilobytes");
    case "mb": return (bytes/Math.pow(1024,2)+" Megabytes");
    case "gb": return (bytes/Math.pow(1024,3)+" Gigabytes");
    case "tb": return (bytes/Math.pow(1024,4)+" Terabytes");
    default:System.out.println("Incorrect notation; Please use\nb\nkb\nmb\ngb\ntb");
            System.exit(0);
            return null;

    }
}

public static String convert_Bytes(long bytes) {
    double Kb=0;
    double Mb=0;
    double Gb=0;
    double Tb=0;
    String result;
    if (bytes>=1024) {
        Kb=bytes/1024;
        bytes=0;
        result=" Kilobytes";
        if(Kb>=1024) {
            Mb=Kb/1024;
            Kb=0;
            result=" Megabytes";
            if(Mb>=1024) {
                Gb=Mb/1024;
                Mb=0;
                result=" Gigabytes";
                if(Gb>=1024) {
                    Tb=Gb/1024;
                    Gb=0;
                    result=" Terabyte";
                }
            }
        }
    }else {
        result=" Bytes";
    }
    double sum=bytes+Mb+Gb+Tb;
    return (sum+result);
}

public static void main(String[] args) {

    String chosen_Folder =args[0];
    String prefered_Unit;
    String full_Size;
    try {
        prefered_Unit =args[1];
    }catch (Exception e) {
        prefered_Unit=null;
    }

    String local_Folder=System.getProperty("user.dir");
    File full_Path;
    String backslash   ="\\";
    String forwardslash="/";
    String seperater;
    if(System.getProperty("os.name").toLowerCase().indexOf("win")>=0) {
        seperater=backslash;
    }else {
        seperater=forwardslash;
    }
    full_Path=new File(local_Folder+seperater+chosen_Folder);



    System.out.println(full_Path);
    long startTime =System.nanoTime();
    if(prefered_Unit!=null) {
        full_Size=convert_Bytes(getFolderSize(full_Path),prefered_Unit);

    }else {
        full_Size=convert_Bytes(getFolderSize(full_Path));
    }
    long endTime =System.nanoTime();

    System.out.println("The size of "+chosen_Folder+" is: "+full_Size);
    System.out.println("Took "+TimeUnit.NANOSECONDS.toSeconds(endTime-startTime)+" seconds to execute.");
    File size_Indicator = new File(full_Path+seperater+"FileSize.txt");
    try {
    size_Indicator.createNewFile();
    FileWriter writer = new FileWriter(size_Indicator);
    writer.write(full_Size);
    writer.close();
    }catch(Exception e) {
        System.err.println(e);
    }

}

}

Author: Percy Jackson, 2018-06-11

1 answers

Juste pour compléter les autres réponses.

Essayez d'éviter d'utiliser

worker = new Thread(new Runnable() {
    ...
  }

Utilisez plutôt un exécuteur. Ils sont beaucoup plus faciles à utiliser, à planifier, à exécuter et à obtenir leurs résultats. De plus, ils s'occupent de la mise en commun des threads et des autres frais généraux que vous avez.

Lire ce .

Les exécuteurs sont disponibles depuis Java 5 et font partie intégrante de toute JVM.

 1
Author: The Impaler, 2018-06-11 17:16:32