|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#21 | ||
|
Member
Iscritto dal: Jan 2005
Messaggi: 81
|
Quote:
Quote:
|
||
|
|
|
|
|
#22 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
E' condiviso perchè tutti i Thread possono accedervi. Probabilmente sarebbe meglio "condivisibile" ma il termine delle specifiche è quello.
Attenzione a non cadere nell'eccesso opposto, cioè "se una cosa non è volatile allora questo codice non è thread-safe". Le norme che stabiliscono cosa sia visibile e cosa non lo sia sono più d'una. Tendono anche al complicato ma è un complicato che, in un certo senso, semplifica. Faccio un esempio. Codice:
class Pippo {
private String value = "hello";
public String getValue() {
return value;
}
}
Codice:
public static void main(String[] args) {
final Pippo pippo = new Pippo();
new Thread() { public void run() {
String x = pippo.getValue();
}}.start();
}
Non c'è volatile, non c'è synchronized e tuttavia è garantito che il secondo Thread leggerà "hello". Lo è perchè c'è una regola che dice che l'azione che avvia un Thread è sincronizzata con la prima azione contenuta nel metodo run di quel Thread e c'è una regola che dice che le azioni in uno stesso Thread sono sincronizzate. Insomma, c'è una sorta di rispetto dell'evidenza.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#23 |
|
Member
Iscritto dal: Jan 2005
Messaggi: 81
|
scusa se continuo a rompere, ma adesso mi si e' sollevato il dubbio e preferirei togliermelo.
dal tuo discorso penso di aver capito che con "condiviso" tu intenda entita' esterne al metodo run, mentre prima pensavo tu ti riferissi a variabili locali del metodo run. detto questo, non sono ancora sicuro di aver capito se il codice che ho postato prima sia un esempio corretto di quanto dicevi in precedenza. vedendo il caso che hai appena riportato, mi verrebbe da dire di si', ma se mi potessi dare la conferma sarebbe meglio grazie mille e scusa ancora per il disturbo
|
|
|
|
|
|
#24 |
|
Senior Member
Iscritto dal: Apr 2000
Città: S.Croce s/Arno - Pisa - Toscana
Messaggi: 1015
|
Adesso la cosa e' piu' chiara. Effettivamente e' giustissimo il discorso sul synchronized dei metodi ma segui questo esempio e la successiva domanda.
Io ho sempre la mia servlet fatta cosi: Codice:
public class MiaClasseServizio extends RemoteServiceServlet {
private volatile DBHandler db = null;
public void init() {
db = new DBHandler(...);
}
public void servizioUno() {
ResultSet rs = null;
rs = db.executeQuery(...);
faccioQualcosa();
int esito = db.executeUpdate(...);
if(esito==1)
db.commit();
else
db.rollback();
}
public void destroy() {
db.close();
}
}
__________________
Il mio album su Flickr :: Video Laurea Honoris Causa ad Alan Kay, Universita' di Pisa :: Thinking Different, PowerBook G4 12" 1GHz, iMac Core 2 Duo 20" |
|
|
|
|
|
#25 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
No.
Ricorda che un riferimento in Java è un puntatore. Cioè è una variabile che contiene un numero, null'altro. La "volatilità" si riferisce a quel numero. Volatile ti dice che se un thread cambia quel valore da 25 a 26 una successiva lettura vedrà 26. Trattandosi di puntatori, qui intendo 25 e 26 come indirizzi di memoria putativi. Opera cioè rispetto al reindirizzamento del puntatore. Non esclude che due Thread possano leggere insieme quel valore. Poichè in Java la lettura di un puntatore avviene solo al fine di accedere ai metodi dell'oggetto puntato, ciò significa che, a prescindere dalla volatilità, due Thread possono invocare contemporaneamente uno stesso metodo di quel DBHandler. Volatile non comporta mutua esclusione.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#26 |
|
Senior Member
Iscritto dal: Apr 2000
Città: S.Croce s/Arno - Pisa - Toscana
Messaggi: 1015
|
Quindi a questo punto devo per forza mettere i metodi di servizio synchronized altrimenti posso avere accessi concorrenti alla connessione. O mi sbaglio anche stavolta?
__________________
Il mio album su Flickr :: Video Laurea Honoris Causa ad Alan Kay, Universita' di Pisa :: Thinking Different, PowerBook G4 12" 1GHz, iMac Core 2 Duo 20" |
|
|
|
|
|
#27 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
E' giusto. E' una soluzione radicale, ma è giusto.
Ma se trasferisci la sincronizzazione ai metodi di DBHandler fai in modo che il codice eseguito in mutua esclusione sia solo quello che effettivamente interagisce con il database. Anche perchè immagino che il metodo di servizio non conterrà solo qualche invocazione ai metodi di DBHandler.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#28 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
x faretto
Sottolineo che qualsiasi dubbio dovrebbe essere risolto facendo riferimento al capitolo 17.4 delle specifiche del linguaggio di programmazione Java. I campi sono condivisi. Le variabili locali non sono condivise. Es: Codice:
public class Pippo {
private String campo = "ciccio";
public void metodo() {
String variabileLocale = "qualcosa";
}
}
Il codice che hai incollato mi pare un po' strano perchè p è sempre null. Per un refuso, immagino. Comunque, supponiamo che ci sia scritto "return (x = new Pippo())", cioè che il singleton sia creato "pigramente". x potrebbe essere null. Non essendo volatile, il Thread che inizializza il singleton è libero di non scrivere mai sull'originale il valore "pippo". Anche il singleton (p) potrebbe essere null.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#29 |
|
Member
Iscritto dal: Jan 2005
Messaggi: 81
|
perfetto, allora pare che abbia capito correttamente
ovviamente il codice era sbagliato, prima di postarlo l'ho modificato, e da bravo fesso ci ho piazzato un errore ![]() grazie ancora per la disponibilita' |
|
|
|
|
|
#30 |
|
Senior Member
Iscritto dal: Apr 2000
Città: S.Croce s/Arno - Pisa - Toscana
Messaggi: 1015
|
Si e' vero pero' non sapendo come funziona internamente l'oggetto Connection ho pensato che se sincronizzo tutto il blocco fino al commit/rollback sicuramente i vari Thread non si influenzano tra di loro.
Se pero' mi dici che posso sincronizzare senza problemi i metodi di DBHandler lo faccio volentieri. In DBHandler ho fondamentalmente questi due metodi: Codice:
public PreparedStatement getPreparedStatement(String sql) throws DBHandlerException {
PreparedStatement pst = null;
try {
pst = conn.prepareStatement(sql);
} catch (SQLException e) {
Logger.logError(this.getClass().toString(), "Impossibile recuperrare il PreparedStatement.");
throw new DBHandlerException("Impossibile recuperrare il PreparedStatement.");
}
return pst;
}
Codice:
public ResultSet executeQuery(String sql) throws DBHandlerException {
ResultSet rs = null;
try {
rs = conn.createStatement().executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
Logger.logError(this.getClass().toString(), "Impossibile eseguire la query.");
throw new DBHandlerException("Impossibile eseguire la query.");
}
return rs;
}
Dici che posso sincronizzare questi e lasciare i metodi di servizio della servlet non sincronizzati?
__________________
Il mio album su Flickr :: Video Laurea Honoris Causa ad Alan Kay, Universita' di Pisa :: Thinking Different, PowerBook G4 12" 1GHz, iMac Core 2 Duo 20" |
|
|
|
|
|
#31 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Guarda, la soluzione che adotterei io è creare un DAO, vale a dire un oggetto che astrae il concetto di base dati ed espone unicamente i metodi necessari alla specifica applicazione.
Ad esempio se le operazioni che devi fare sono salvare un Record, aggiornare un Record, eliminare un Record, cercare un Record, il DAO diventa una cosa tipo: Codice:
public class DAO {
public synchronized void open() {...}
public synchronized void close() {...}
public synchronized long saveRecord(RecordData r) {...}
public synchronized void updateRecord(long id, RecordData rd) {...}
public synchronized void deleteRecord(long id) {...}
public synchronized Collection<Record> findRecord(RecordData r) {...}
}
Se prendi la connessione e gli tiri fuori un ResultSet tout-court altro non fai che spostare l'esigenza della mutua esclusione da DBHandler al codice che usa DBHandler perchè nè result-set nè statement sono di per sè adatti all'uso concorrente. Dobbiamo infatti ricordare che anche la scansione dei risultati contenuti in un ResultSet può tradursi nell'esecuzione di ulteriori operazioni sulla base dati. D'altro canto la sincronizzazione è sufficiente per il primo metodo, quello che crea un PreparedStatement. Insomma, si può fare anche così ma a me sembra più complicato rispetto al DAO "classico".
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#32 |
|
Senior Member
Iscritto dal: Apr 2000
Città: S.Croce s/Arno - Pisa - Toscana
Messaggi: 1015
|
Ti ringrazio davvero tanto per il tuo aiuto e la tua pazienza.
__________________
Il mio album su Flickr :: Video Laurea Honoris Causa ad Alan Kay, Universita' di Pisa :: Thinking Different, PowerBook G4 12" 1GHz, iMac Core 2 Duo 20" |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 03:29.





















