[MultiThreading] Manager Thread

di il
9 risposte

[MultiThreading] Manager Thread

Voglio realizzare un piccolo gestore dei thread di un server, utilizzabile interattivamente da console.
Il server genera tanti thread. In un dato momento posso sapere il nome dei thread nello stato Runnable. Voglio poter sospendere e riprendere o eliminare i thread a mio piacimento dal nome.
Esempio di codice:

public class Manager{

	private MongoDB db = MongoDB.getInstance();
	
	public void generaT(long c){
		Thread d = new Thread(()->genera(c));
		d.setName(c+"");
		d.start();
	}

	public void genera(long c){
		long sum=0;
			for(long i=c; i<9999999999L ; i++)
			{
				sum+=i;
			}
			db.insert(sum);
	}
	
	public void print(){db.visualize();}
	
	public void start(){
		Scanner scanner = new Scanner(System.in);
		String in = "";
		
		while(!in.equals("quit")){
			in = scanner.nextLine();
				switch(in){
				
					case "genera" : 
							int c = Integer.parseInt(scanner.nextLine());
							generaT(c);
						break;
						
					case "print" : print();
						break;
						
					case "list" : 
						for(Thread t : Thread.getAllStackTraces().keySet()){
							System.out.println("Nome = "+t.getName()+""
							+" Stato = "+t.getState());
						}
						break;
						
					case "stop" : 
						String th = scanner.nextLine();
						for(Thread t : Thread.getAllStackTraces().keySet()){
							if(t.getName().equals(th)){
							t.wait();}
						};break;
						
					case "resume" :
						String thh = scanner.nextLine();
						for(Thread t : Thread.getAllStackTraces().keySet()){
							if(t.getName().equals(thh)){
								t.notify();
							}
						};
						break;
			
					default: break;
				
				}		
		}
	
	}
	
	
	
	public static void main(String[] args) throws InterruptedException {
		Manager s = Manager.geInstance();
		s.start();
	}
}

Dato che suspend, stop e resume sono deprecati, quale meccanismo per cambiare lo stato dei threads va utilizzato?
Così facendo mi lancia "IllegalMonitorStateException". Ho appena notato che digitando "quit" non esce nemmeno dal while

Grazie e buon weekend

9 Risposte

  • Re: [MultiThreading] Manager Thread

    La questione e' complicata!
    Le suspend/resume sono state deprecate (e andrebbero anche rimosse) perche' sospendono il thread SENZA TENERE CONTO di che cosa il thread stava facendo in quel momento: poteva essere in mezzo ad un calcolo, alla scrittura di un file, alla ricezione di un video, ...

    La soluzione e' implementare un TUO meccanismo di suspend, mediante un oggetto di sicronizzazione che imposti a true/false dall'esterno e il thread, all'interno del suo loop di esecuzione, nel posto piu' congegnale, testa con una certa regolarita'.

    Quando l'oggetto diventa true (o false), il thread si sospende, mentre quando gli viene cambiato stato, il thread viene fatto ripartire.

    In questo modo la sospensione (che ovviamente NON PUO' ESSERE ISTANTANEA, ma averra' al prossimo test del flag, quindi al termine dei lavori correnti) averra' in un momento in cui il thread puo' permettersi di sospendersi.
  • Re: [MultiThreading] Manager Thread

    Capito.
    Questo esempio potrebbe andare bene??
    http://www.tutorialspoint.com/java/java_thread_control.htm

    Grazie.
  • Re: [MultiThreading] Manager Thread

    Paolovox ha scritto:


    Questo esempio potrebbe andare bene??
    http://www.tutorialspoint.com/java/java_thread_control.htm
    Sì, il concetto è quello. Solo un appunto: anche quel void suspend() DEVE essere synchronized ! Se suspend() non è synchronized, allora la soluzione è mettere la variabile suspended come volatile.

    Il punto è che per la terminazione/sospensione, il codice del thread deve "cooperare". E per la sospensione la cooperazione consiste appunto in quel blocco synchronized in cui viene usato il wait in ciclo testando la condizione di suspended.


    La documentazione ufficiale che spiega perché i metodi destroy/stop/resume/suspend di Thread sono deprecati (e come risolvere) è quella di Oracle: Java Thread Primitive Deprecation
  • Re: [MultiThreading] Manager Thread

    Grazie mille.
    Adesso comincio a leggere
  • Re: [MultiThreading] Manager Thread

    Cosa fa il modificatore di accesso volatile?

    Adesso ho creato la mia classe MyThread con i metodi start, suspend, resume simile all'esempio ma con le correzioni che mi avete suggerito.
    Poi man mano che li genero, dovrei poterli conservare in una struttura dati adeguata per monitorarli e sospenderli e riprenderli.
    Quale struttura dati posso utilizzare?

    Buona domenica
  • Re: [MultiThreading] Manager Thread

    Paolovox ha scritto:


    Cosa fa il modificatore di accesso volatile?
    Garantisce che tutti i thread vedano un valore consistente, anche in un contesto senza sincronizzazione. Più precisamente è garantito che una lettura legga davvero e senza alcun dubbio l'ultimo valore scritto da qualunque altro thread. Cosa che senza sincronizzazione normalmente non è garantita.

    Attenzione: volatile garantisce la "visibilità" delle modifiche ma NON la "atomicità". Quindi non va bene se una variabile numerica è usata es. con var++ (che è fatto da 3 operazioni distinte: leggi-incrementa-scrivi) che può comunque causare una race-condition.
    Va bene invece quando es. c'è un flag booleano che viene scritto da un certo thread e letto da un solo altro thread. Che è appunto quel caso che hai trovato.

    Paolovox ha scritto:


    dovrei poterli conservare in una struttura dati adeguata per monitorarli e sospenderli e riprenderli.
    Quale struttura dati posso utilizzare?
    Senza sapere altro di specifico ... una lista dovrebbe bastare.
  • Re: [MultiThreading] Manager Thread

    Grazie mille funziona alla perfezione. Ora ho solo un altro piccolo grattacapo.
    Man mano che genero i threads li inserisco in una lista, ma quando il loro compito è giunto al termine, dovrei eliminarli dalla lista.
    La classe MyThread ha un metodo isFinished().
    Quale strategia adotto per l'eliminazione dei threads finiti?
    Creo un nuovo thread, con bassa priorità che scandisce la lista di threads e controlla quelli finiti per cancellarli?

    Dato che il numero di threads da generare dovrà essere a dir poco abnorme, è possibile sapere il numero max di threads generabili, la dimensione massima della lista dei threads, vado incontro a qualche eccezione da gestire? Non vorrei ritrovarmi nei casini e il mondo della programmazione multithreading è ancora sconosciuto a me, dato che a settembre comincerò il corso in merito.
  • Re: [MultiThreading] Manager Thread

    Paolovox ha scritto:


    ma quando il loro compito è giunto al termine, dovrei eliminarli dalla lista.
    La classe MyThread ha un metodo isFinished().
    Quale strategia adotto per l'eliminazione dei threads finiti?
    Di base, e detto in generale, Thread ha il metodo join() (sia con attesa infinita sia con timeout) per attendere la terminazione di un altro thread. Quindi vorrebbe dire fare un ciclo continuo con un join a timeout basso in modo testare regolarmente tutti i thread. Ma con TANTI thread non sarebbe sicuramente molto efficiente.

    Paolovox ha scritto:


    Creo un nuovo thread, con bassa priorità che scandisce la lista di threads e controlla quelli finiti per cancellarli?
    Potrebbe .... forse ... ma è da provare.

    Paolovox ha scritto:


    è possibile sapere il numero max di threads generabili
    Un thread consuma un numero di risorse abbastanza considerevole. Il numero massimo di thread dipende da molti fattori: sistema operativo, n. di core, memoria (sia nativa, sia intendendo il heap space di Java), probabilmente anche la implementazione della JVM. E sicuramente altro.


    Paolovox ha scritto:


    la dimensione massima della lista dei threads, vado incontro a qualche eccezione da gestire?
    Tentando di sfruttare molte risorse, sicuramente si va verso l'eventualità di eccezioni. Ma se ti becchi es. OutOfMemoryError o altre del genere ... generalmente c'è ben poco/nulla che puoi aggiustare ...

    Paolovox ha scritto:


    Non vorrei ritrovarmi nei casini e il mondo della programmazione multithreading è ancora sconosciuto a me, dato che a settembre comincerò il corso in merito.
    Ma questa è la prima cosa che fai con il multi-threading (che banale non mi sembra)? O hai già fatto programmini ben PIU' semplici di questo? Perché il multi-threading è un campo molto "minato" ....
  • Re: [MultiThreading] Manager Thread

    Vi ringrazio nuovamente per tutti i consigli utilissimi che ogni volta mi illuminano molto.

    E' la prima volta che li devo utilizzare, ancora non abbiamo fatto la Fork/Join o gli ExecutorService che sarà in un corso specifico a settembre. Quindi utilizzerò il semplice Thread sempre per completare il server dei Cruciverba. Utilizzando Tomcat, MongoDB e il CruciverbaBuilder (algoritmo sia in backtracking per server piccoli che in programmazione dinamica per server possenti) in multithreading devo generare tutti i possibili cruciverba di uno specificato schema, dominio e difficoltà, memorizzarlo in MongoDB in formato JSON con tutti gli attributi utili e spedirlo al client. Non utilizzo più la serializzazione dipendente dalla versione di Java che già mi aveva dato problemi da Java 8 a 7. E' un progettino universitario siamo in pochi e per novembre dovremmo pubblicare una piccola app free e open source per android, web, ios di un cruciverba un pò alternativo (grafica in LibGDX). Ed è grazie anche a tanta gente come voi, che ci offre dai piccoli ai grandi aiuti gratuitamente e in modo simpatico, che il progettino sta riuscendo.

    Non capisco però come far suicidare i miei poveri threads quando terminano la loro esecuzione.
    Ecco un piccolo esempio:

    ===Thread===
    
    public class CrucyThread implements Runnable{
    
    	private Thread t;
    	private String name;
    	private volatile boolean suspend;
    	
    	public CrucyThread(Schema schema, String dominio, float difficoltà)
    	{
    		......
    	}
    	
    	@Override
    	public void run() {
    		//Cruciverba Builder ...
    	}
    	
    	public void start(){
    		if ( t == null){
    			t = new Thread(this,name);
    			t.start();
    		}
    	}
    	
    	public synchronized void suspend(){
    		suspend = true;
    	}
    	
    	public synchronized void resume(){
    		suspend = false;
    		notify();
    	}
    	
    	public String getName(){return name;}
    
    }
    
    ===Generatore===
    
    public class CrucyGen {
    
    	private CrucyDB cdb = CrucyDB.getInstance();
    	private List<CrucyThread> lct = new ArrayList<>();
    	
    	
    	public synchronized void generaT(Schema schema, String dominio, float difficoltà)
    	{
    		CrucyThread ct = new CrucyThread(schema,dominio ,difficoltà);
    		lct.add(ct);
    		ct.start();	
    	}
    	
    	public void start() ........
    	......
    	......
    
Devi accedere o registrarti per scrivere nel forum
9 risposte