DOMANDA [JAVA] Differenze tra ArrayList e Vector

Alessandro001

Utente Attivo
166
7
CPU
Ryzen 5 1600 3.2GHz
Scheda Madre
MSI B350 Tomahawk
HDD
Seagate ST1000DM010 1 TB
RAM
2X8GB Corsair CMK16GX4M2B3000C15 Vengeance
GPU
RADEON RX 580 NITRO+ Radeon RX 580 8GB GDDR5
Monitor
HP 27FW Monitor 27"
PSU
Cooler Master MasterWatt Lite 700 230V
Case
Aerocool Aero-800
Net
https://www.speedtest.net/result/8773872068.png
OS
Windows 10
Salve, oltre alle differenze citate di seguito tra ArrayList e Vector quali altre sostanziali differenze ci sono tra le due classi? E cosa si intende per metodi sincronizzati? Inoltre ho notato che i metodi della classe ArrayList sono quasi tutti contenuti nella classe Vector...

1) I metodi di Vector sono sincronizzati, mentre quelli di ArrayList non lo sono.
2) Vector fornisce, con metodi e costruttori, un controllo maggiore sulla capacità, e sulla dimensione dell'array.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Il punto fondamentale è il primo. Vector è sincronizzato, quindi è da usare con il multithreading.

Se non erro anche l'implementazione interna è uguale nel modo in cui gli elementi vengono allocati, ma in questo potrei errare.
 
  • Mi piace
Reazioni: Alessandro001

Alessandro001

Utente Attivo
166
7
CPU
Ryzen 5 1600 3.2GHz
Scheda Madre
MSI B350 Tomahawk
HDD
Seagate ST1000DM010 1 TB
RAM
2X8GB Corsair CMK16GX4M2B3000C15 Vengeance
GPU
RADEON RX 580 NITRO+ Radeon RX 580 8GB GDDR5
Monitor
HP 27FW Monitor 27"
PSU
Cooler Master MasterWatt Lite 700 230V
Case
Aerocool Aero-800
Net
https://www.speedtest.net/result/8773872068.png
OS
Windows 10
Il punto fondamentale è il primo. Vector è sincronizzato, quindi è da usare con il multithreading.

Se non erro anche l'implementazione interna è uguale nel modo in cui gli elementi vengono allocati, ma in questo potrei errare.
Guarda io avevo un programma gestito totalmente con l'ArrayList e cambiando ArrayList con Vector funziona perfettamente tutto ed anche meglio perchè la size non viene moltiplicata ogni volta ma dal costruttore di Vector scelgo io di quanto incrementare ogni volta...
Comunque non mi è molto chiaro il primo punto non avendo molta esperienza della programmazione Java in multithreading ...
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,918
11,562
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Il primo punto è quello chiave: se non ci sono più thread che usano la stessa struttura dati, l'ArrayList ha prestazioni superiori rispetto a Vector perché non implementa nessun controllo di sincronizzazione. Il funzionamento interno invece è quasi identico, alla fin fine sono entrambi degli array ridimensionabili e differiscono solo per il fattore di crescita auotmatica (se non ricordo male il vector raddoppia le dimensioni quando esarurisce lo spazio inizialmente allocato, invece l'ArrayList le incrementa del 50%)
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Tieni presente che estendono la stessa classe e implementano le stesse interfaccie (giusto per far notare che sono uguali).
Si, con Vector il costruttore permette di specificare anche l'incremento quando il limite viene raggiunto.

La differenza è molto importante (mentre scrivevo ho notato la risposta di BAT, che sottoscrivo): nel caso di multithreading con Java puoi evitare che un blocco di codice, o un metodo, venga acceduto da più di 1 thread alla volta; per far ciò si utilizza la parola chiave synchronized.

Per fare un esempio, questa l'implementazione di add() di Vector:

Java:
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

Questo è invece quello di ArrayList:
Java:
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

utilizzando i metodi sincronizzati, o in generale sincronizzando una parte del codice, si è sicuri che solo 1 thread acceda ad una risorsa.
Se non utilizzi Vector devi gestire tu stesso questi aspetti.

La capacità cresce - guardando il sorgente - in questo modo per Vector (non riporto il controllo sul numero < 0 o superiore alla capacità massima per semplicità):
Java:
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

e questo è quello di ArrayList:
Java:
int newCapacity = oldCapacity + (oldCapacity >> 1);

quindi la dimensione di ArrayList, come dice BAT, cresce del 50% (oldCapacity >> 1, equivale a oldCapacity / 2), mentre quella di Vector del 100% se non viene specificato il parametro capacityIncrement (quello che citavi tu inizialmente).

Insomma, in pratica: senza multithreading ti converrebbe ArrayList. Se lo trovi lento probabilmente dipende dalla quantità di allocazioni: hai tanti elementi da memorizzare, e raggiungi velocemente quel 50% in più che viene allocato da ArrayList; questo provoca ovviamente un maggior numero di allocazioni.
Oppure, il parametro che tu passi a Vector è maggiore al 50% di ArrayList, quindi allochi più memoria, ma fai meno allocazioni ("sprecandone" di più).

Per il resto anche se guardi i sorgenti noterai le similitudini (li trovi zippati nella cartella del JDK).
 
  • Mi piace
Reazioni: Alessandro001

Alessandro001

Utente Attivo
166
7
CPU
Ryzen 5 1600 3.2GHz
Scheda Madre
MSI B350 Tomahawk
HDD
Seagate ST1000DM010 1 TB
RAM
2X8GB Corsair CMK16GX4M2B3000C15 Vengeance
GPU
RADEON RX 580 NITRO+ Radeon RX 580 8GB GDDR5
Monitor
HP 27FW Monitor 27"
PSU
Cooler Master MasterWatt Lite 700 230V
Case
Aerocool Aero-800
Net
https://www.speedtest.net/result/8773872068.png
OS
Windows 10
Tieni presente che estendono la stessa classe e implementano le stesse interfaccie (giusto per far notare che sono uguali).
Si, con Vector il costruttore permette di specificare anche l'incremento quando il limite viene raggiunto.

La differenza è molto importante (mentre scrivevo ho notato la risposta di BAT, che sottoscrivo): nel caso di multithreading con Java puoi evitare che un blocco di codice, o un metodo, venga acceduto da più di 1 thread alla volta; per far ciò si utilizza la parola chiave synchronized.

Per fare un esempio, questa l'implementazione di add() di Vector:

Java:
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}

Questo è invece quello di ArrayList:
Java:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

utilizzando i metodi sincronizzati, o in generale sincronizzando una parte del codice, si è sicuri che solo 1 thread acceda ad una risorsa.
Se non utilizzi Vector devi gestire tu stesso questi aspetti.

La capacità cresce - guardando il sorgente - in questo modo per Vector (non riporto il controllo sul numero < 0 o superiore alla capacità massima per semplicità):
Java:
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

e questo è quello di ArrayList:
Java:
int newCapacity = oldCapacity + (oldCapacity >> 1);

quindi la dimensione di ArrayList, come dice BAT, cresce del 50% (oldCapacity >> 1, equivale a oldCapacity / 2), mentre quella di Vector del 100% se non viene specificato il parametro capacityIncrement (quello che citavi tu inizialmente).

Insomma, in pratica: senza multithreading ti converrebbe ArrayList. Se lo trovi lento probabilmente dipende dalla quantità di allocazioni: hai tanti elementi da memorizzare, e raggiungi velocemente quel 50% in più che viene allocato da ArrayList; questo provoca ovviamente un maggior numero di allocazioni.
Oppure, il parametro che tu passi a Vector è maggiore al 50% di ArrayList, quindi allochi più memoria, ma fai meno allocazioni ("sprecandone" di più).

Per il resto anche se guardi i sorgenti noterai le similitudini (li trovi zippati nella cartella del JDK).
Davvero ottime risposte le vostre.
Ho capito tutto e vi ringrazio!

Inviato da SNE-LX1 tramite App ufficiale di Tom\'s Hardware Italia Forum
 
  • Mi piace
Reazioni: DispatchCode

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili