简体   繁体   中英

Java Thread Synchronized

This program runs 4 threads and searches for prime numbers from 1 to 100. Sometimes 2 threads are simultaneously attacking and numbers are repeated. I tried to synchronize the thread but I do not know how to do it well. Can I you can help? Sorry for my bad English

import java.util.ArrayList;

public class EjemploThread1 extends Thread{

    static int numero=1;
    static ArrayList<Integer> primos = new ArrayList<Integer>() ; 

    public synchronized void run() {
        //try {
        while (numero < 100){
            numero++;

            if (!primos.contains(numero) && esPrimo(numero))
            {
                primos.add(numero);
            }

            notifyAll();

            //yield();
            try {
                sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }


    //MAIN
    public static void main(String[] args) throws InterruptedException {

        EjemploThread1 hilos = null;

        int n_hilos=4;

        //Crear los 4 Hilos
        for (int i=0;i<=n_hilos;i++) {
            hilos = new EjemploThread1();
            hilos.start();
        }

        for (int i=0;i<=n_hilos;i++) {
            hilos.join(); 
        }

        //cuando finalizen los hilos(join) continuara y mostrara el vector:
        System.out.println("\nVECTOR NUMEROS PRIMOS: ");
        for(int i=0; i < primos.size(); i++)
        {
            System.out.print(primos.get(i) + " ");  
        }
    }

    //FUNCION SABER SI ES PRIMO
    public static boolean esPrimo(int numero)
     {
        for(int i=2; i<numero; i++)
        {
            if(numero % i == 0) return false; //no es primo
        }         
        return true; //es primo
     }
}

It would be easier to divide up your search space among the Thread s when you initialize them so you have no overlap. No clunky synchronization needed. Something like this.

public class PrimeFinder implements Runnable {

    private int rangeStart;
    private int rangeEnd;

    public PrimeFinder(int start, int end) {
        rangeStart = start;
        rangeEnd = end;
    }

    public void run() {
        //check for primes where rangeStart <= x <= rangeEnd
    }
}

... then in main ...

public static void main(String[] args) {
    new Thread(new PrimeFinder(0, 25)).start();
    new Thread(new PrimeFinder(26, 50)).start();
    //and so on
}

As a side note, synchronized -ing the run method of your Thread s is useless. Each Thread gets its own run method, so nothing else ever competes for that particular lock.

In response to your comment:

If you're forced to do it this way and don't want duplicate numbers added to your list, you can synchronize a wrapper method to add the primes:

public static synchronized void addPrime(int prime) {
    if(!primos.contains(prime)) {
        primos.add(prime);
    }
}

This will ensure that you get no duplicates. Then in your Thread you would have:

if(esPrimo(numero)) {
    addPrime(numero);
}

instead of synchronizing run() you could synchronize the static arrayList primos:

 List primos = Collections.synchronizedList(new ArrayList<Integer>());

This ensures that no two threads will test the same number

I think synchronizing run() on a Runnable is never a good idea. I would simply declare numero as volatile or change its type to AtomicInteger

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM