Garu
Garu

Reputation: 1179

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
     }
}

Upvotes: 2

Views: 479

Answers (3)

Diferdin
Diferdin

Reputation: 1260

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

Upvotes: 0

asteri
asteri

Reputation: 11572

It would be easier to divide up your search space among the Threads 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 Threads 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);
}

Upvotes: 2

deanosaur
deanosaur

Reputation: 611

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

Upvotes: 0

Related Questions