Keresés

Részletes keresés

el Papi Creative Commons License 2010.10.07 0 0 5490
Gyakori felreertes a class es a thread osszekeverese ilyenkor.
A te eseted sokkal egyszerubben (es olvashatobban):

Class MyThread extends Thread{

private int counter = 0;
private final Object mutex = new Object();

void run(){
for(...){
synchronized(mutex){
... k++, k---, whatever;
}
}
}

public int getCounter(){
synchronized(mutex){
return counter;
}
}

public void setCounter(int c){
synchronized(mutex){
this.counter = c;
}
}

}


Class OtherThread extends Thread{

private MyThread myThread;

OtherThread(String name, MyThread myThread){
super(name);
this.myThread = myThread;
}

void run(){
for(..){
... get/setCounter(...)
}
}
}
Előzmény: bigzed (5487)
angyalhentes Creative Commons License 2010.10.07 0 0 5489
Javában hamar hozzá fogsz szokni ahhoz, hogy mindenhez wrappert csinálj. Sokakat bosszant, de szerintem ha nem ész nélkül csinálja az ember, a végeredmény sokkal olvashatóbb.
Előzmény: bigzed (5487)
bigzed Creative Commons License 2010.10.07 0 0 5488
hihi!

Fejlodom, ugy tunik. Meg ezen hozzaszolasod elott potyogtem be a magamet. :))))
Előzmény: el Papi (5486)
bigzed Creative Commons License 2010.10.07 0 0 5487
igen ez volt a cel.
A benazasom onnan indult, hogy nem akartam sajat osztalyt kesziteni egy nyomoronc counter kedveert, es olyan siman elsiklottam az Integer immutable volta felett, hogy meg magam is kinevettem magam. Nem megy sajat "Integer" class nelkul a dolog.

(Koszonet el Papinak, hogy ismetelten folhivta erre a figyelmemet. )


Aztan mostmar megemesztettem azt is, hogy ezen a modon ahogy en csinatam nem eleg, ha az egyik szal hasznal egy lockot. Itt talan megis objektum orientalt vagyok :D , ha nagyon szeretnem egy objektumhoz kotni a lockolas problematikajat, es mas objektumnal ami hozzaferne a kritikus szalbiztos valtozohoz, mar nem szeretnek mindenfele lockokkal bajlodni, a tobbi szal ne is tudjon a dologrol, legyen az a szalbiztos valtozot tartalmazo obj dolga.

Ez viszont valoban csak szinkronizalt setter/getter metodusokkal megy, nem szinkronizalhatok a valtozora.
Előzmény: el Papi (5482)
el Papi Creative Commons License 2010.10.07 0 0 5486
Tobb problema van:
statikus hivatkozas instance-on keresztul.
az objektum orientalt nyelvbol eredoen nem modositunk/olvasunk direkt valtozokat, plane nem multthreading kornyezetben.
Egy mutexet nagyon nem szerencses kulonbozo classokban hasznalni. En csinaltam anno ilyet elsosorban performance okok miatt, de ezzel gyakorlatilag oda is lett a kodom karbantarthatosaga. Nagyon kenyes dolog az ilyesmit debugolni, es akkor gondolj bele abba, ha nem is a sajat kododrol van szo.
Szoval mindig igyekezz hazon (classon) belul tartani a thread safety-t biztosito kodot.
Előzmény: bigzed (5483)
bigzed Creative Commons License 2010.10.07 0 0 5485
:) oooo! szemafor ugyben meg ugyetlenebb vagyok.
Előzmény: angyalhentes (5478)
bigzed Creative Commons License 2010.10.07 0 0 5484
Nincs problema. Egy szerencsetlen szamlalot probalok ket szallal toszogatni ugy, hogy bizonyos helyeken a kodban biztonsagban erezzem magam, ezeken a helyeken ne kaphasson lehetoseget mas szal.
Előzmény: el Papi (5481)
bigzed Creative Commons License 2010.10.07 0 0 5483
Ez kivitelezheto, de nagyon nem ajanlott ilyet csinalni.

Miert nem ajanlott ez? Mi a gond ezzel?
Előzmény: el Papi (5477)
el Papi Creative Commons License 2010.10.07 0 0 5482
Amennyiben az a celod, hogy a SimpleCount1 peldanyod ciklusmagjanak mukodese olyan legyen hogy minden iteracional kiirt szampar kozti kulonbseg 1 legyen, akkor igen.
Előzmény: bigzed (5480)
el Papi Creative Commons License 2010.10.07 0 0 5481
Szerintem is az lenne a legszerencsesebb ha a eloszor is tisztaznank mi az alapveto megoldando problema.
Előzmény: angyalhentes (5478)
bigzed Creative Commons License 2010.10.07 0 0 5480
igy mar akkor ok?!

class SimpleCount2 extends Thread {
Thread masikSzal;
SimpleCount2(String name, Thread masikSzal) {
super(name);
this.masikSzal = masikSzal;
}
public void run() {
for (int i = 1; i <= 500; ++i)
synchronized ( ((SimpleCount1) masikSzal).myInteger ){
((SimpleCount1) masikSzal).myInteger.incIntValue(2);
}
}
}
Előzmény: el Papi (5476)
el Papi Creative Commons License 2010.10.07 0 0 5479
((SimpleCount1) masikSzal).myInteger.incIntValue(2);

Itt egy instance-bol probalsz hivatkozni egy statikus mezore. Teljesen felesleges a 'masikSzal'. Az alabbi teljesen ugyanezt csinalja es olvashatobb:

SimpleCount1.myInteger.incIntValue(2);

Amugy az objektum orientacio alapelveivel utkozik egy ilyen direkt valtozo eleres.
Előzmény: bigzed (5474)
angyalhentes Creative Commons License 2010.10.07 0 0 5478
Tehát akkor lényegében egy szemaforra lenne szükséged?

Nekem erősen az az érzésem, hogy túl messzire elmentél egy irányban a megoldás fele, mielőtt még tisztáztad volna, mi a megoldandó probléma.
Előzmény: bigzed (5475)
el Papi Creative Commons License 2010.10.07 0 0 5477
Ehhez az kene, hogy a SimpleCount2-ben szereplo MyInteger modosito muvelet is ugyanazon lock-ot szerezze meg.
azaz synchronized(SimpleCount1.myInteger) {...}

Ez kivitelezheto, de nagyon nem ajanlott ilyet csinalni.
Előzmény: bigzed (5475)
el Papi Creative Commons License 2010.10.07 0 0 5476
Ez egyaltalan nem thread safe. A SimpleCount2 peldanyod minden akadaly nelkul fogja a MyInteger-edet modositani, es SimpleCount1 peldanya is, mivel csak o hasznalja a lockot.
Előzmény: bigzed (5474)
bigzed Creative Commons License 2010.10.07 0 0 5475
synchronized (myInteger) {
System.out.print( getName()+ ":" + myInteger.getIntValue()+" ");
myInteger.incIntValue(1);
System.out.println( getName()+ ":" + myInteger.getIntValue());
}

az lenne a feladat, hogy a ket kiiras altal szolgaltatott ertek kozott mindig 1 legyen a kulonbseg
Előzmény: bigzed (5474)
bigzed Creative Commons License 2010.10.07 0 0 5474
Ez biztositana?

package threadproba1;

class MyInteger {
private int i;
MyInteger(int i) { this.i = i; }
public void incIntValue(int n) { i+=n; }
public int getIntValue() { return (i); }
}

class SimpleCount2 extends Thread {
Thread masikSzal;
SimpleCount2(String name, Thread masikSzal) {
super(name);
this.masikSzal = masikSzal;
}
public void run() {
for (int i = 1; i <= 50; ++i)
((SimpleCount1) masikSzal).myInteger.incIntValue(2);
}
}

public class SimpleCount1 extends Thread {
volatile static MyInteger myInteger = new MyInteger(0);
SimpleCount1(String name) {
super(name);
}

public void run() {
for (int i = 1; i <= 50; ++i) {
synchronized (myInteger) {
System.out.print( getName()+ ":" + myInteger.getIntValue()+" ");
myInteger.incIntValue(1);
System.out.println( getName()+ ":" + myInteger.getIntValue());
}
}
}
public static void main(String[] args) {
Thread thread1 = new SimpleCount1("th1"), thread2 = new SimpleCount2("th2", thread1);
thread1.start();
thread2.start();
}
}

thread1
Előzmény: el Papi (5473)
el Papi Creative Commons License 2010.10.07 0 0 5473
Ha multithread kornyezetben egy valtozot tobb thread hasznal egyszerre, akkor biztositani kell explicit vagy implicit a szalbiztonsagot.
"Magatol" nem lesz szalbiztos. A te esetedre ott van az AtomicInteger amivel implicit biztositod a szalbiztonsagot. Ha olyan adattipust hasznalsz ahol ez nincs biztositva, ott ez neked kell explicit elvegezni.
Előzmény: bigzed (5472)
bigzed Creative Commons License 2010.10.07 0 0 5472
ez vilagos:

private int k;

public void setK(int k){
synchronized(mutex){
this.k=k;
}
}


ugy kerulod meg a problemat, hogy nem engeded, hogy egy masik szal kozvetlenul hozzaferjen a k valtozohoz, csak a publikalt es szinkronizalt setK() metodussal.

tehat nem k-ra szinronizalsz (primitivre ugyebar nem is lehet), hanem eldugod k-t, hogy hozza se ferjen semmifele szal, es a beallito metodust szinkronizalod, egy csak erre a szinkronizalcio celjara gyartott mutex-szel.

Tehat megkerulod a problemat. :)

Akkor az nem muxik, hogy egy pl osztalyszintu publikus, statikus countert szalbiztosan kezeljunk kozvetlenut setter()/getter() metodusok kihagyasaval?
Előzmény: el Papi (5470)
el Papi Creative Commons License 2010.10.07 0 0 5471
A masodik peldaban benne maradt a getter deklaracioban a synchronized, az ertelemszeruen nem kell oda.
Előzmény: el Papi (5470)
el Papi Creative Commons License 2010.10.07 0 0 5470
el Papi!
Megprobalom osszfoglalni a korabbiakat:
Idaig azon gorcsoltunk, hogy Integer nem, Object mutex igen, meg hogy ertheto okbol ez azert legyen static...

Object mutex nem ok, ez kiderul, ha jol latom. Igy van?

Javitsatok ki, ha nem jol gondolom, most tehat ott tartunk, hogy a mutexes megoldas zsakutca, vegyuk elo a synchronizalt getter-setter megoldast, es csak ne nyulkajak k-hoz mas szalakbol publikusan.


Class MyClass{
private int k;

public synchronized void setK(int k){
this.k=k;
}

public synchronized int getK(){
return this.k;
}
}

es ugyanez kulso monitorlockal:

Class MyClassWithMutex{
private int k;

private final Object mutex = new Object();

public void setK(int k){
synchronized(mutex){
this.k=k;
}
}

public synchronized int getK(){
synchronized(mutex){
return this.k;
}
}
}

A kulonbseg az hogy az elso verzioban synchronized(this) a masodikban pedig synchronized(mutex) van.

Előzmény: bigzed (5469)
bigzed Creative Commons License 2010.10.07 0 0 5469
angyalhentes kodja es magyarazta nem eleg vilagos nekem (talan nemi eliras is lehet benne).
Picit lehetne reszletesebben, kezdok szamara is erthetobben?

class SyncInt {
private final Object lock = new Object();
private int k;

public final void execute( SyncBlock block) {
synchronized( block ) {
k = block.syncExecute( k );
}
}

}

interface SyncBlock {
public int syncExecute( int currentValue );
}


Mas:

"Ugy hogy a counter-t private mezove teszed es enkapszulalod a modosito muveleteit. Ezt akar egy synchronizalt getter-setter komboval is el lehet erni."

el Papi!
Megprobalom osszfoglalni a korabbiakat:
Idaig azon gorcsoltunk, hogy Integer nem, Object mutex igen, meg hogy ertheto okbol ez azert legyen static...

Object mutex nem ok, ez kiderul, ha jol latom. Igy van?

Javitsatok ki, ha nem jol gondolom, most tehat ott tartunk, hogy a mutexes megoldas zsakutca, vegyuk elo a synchronizalt getter-setter megoldast, es csak ne nyulkajak k-hoz mas szalakbol publikusan.


Előzmény: el Papi (5462)
el Papi Creative Commons License 2010.10.07 0 0 5468
Igen, erre probaltam felhivni a figyelmet :-) , de eppen ezert mondtam, hogy egy olyan kodnal amit teljes mertekben az fejleszto kontrollja alatt van, ott nem erdemes pl. extra interface-kkel bonyolitani, egyszeruen ossze kell hangolni a mutex-et.

Ha viszont van egy public szolgaltatasod amihez van egy API aminek command pattern jelleggel lehet utasitasokat kuldeni neki, akkor ott viszont nagyon kell figyelni, ne adjon az ember teret semelyik "kreativ" fejlesztotarsanak sem.
Előzmény: angyalhentes (5467)
angyalhentes Creative Commons License 2010.10.07 0 0 5467
Nem, nem kell figyelni.

Ha valaki minden erejét mozgósítja, hogy tökönszúrja magát, azt hagyni kell. :)
Előzmény: el Papi (5466)
el Papi Creative Commons License 2010.10.07 0 0 5466
Ez garantálja azt, hogy amíg a syncExecute() fut, addig senki nem piszkál hozzá k-hoz. A különböző műveleteid mind a SyncBlock implementációi lesznek, de ez nem okoz gondot, mert másképp nem lehet hozzáférni k értékéhez.

Ha nagyon szorszalhasogatoak vagyunk akkor ez sem teljesen igaz. :-)
Reflection illetve bytecode injection nevu modszerekkel ez is megkerulheto. Erre akkor kell figyelni ha vmilyen public API-t adsz ki.
Előzmény: angyalhentes (5461)
el Papi Creative Commons License 2010.10.07 0 0 5465
main-ben sleep-ej picit run utan, amig veget nem ertnek a thread-ek

thread.join()
Előzmény: crockl (5463)
crockl Creative Commons License 2010.10.07 0 0 5464
bocs az eleje visszavonva, baromsag. a ++, -- masolat miatt persze hogy elcsuszik, csak maga az 1-1 muvelet atomic, de itt ugye ertek adasnal nem csak 1 van beloluk.
Előzmény: crockl (5463)
crockl Creative Commons License 2010.10.07 0 0 5463
ebben az esetben nem igaz amit mondasz, marmint a volatile itt garantalja, hogy egyszerre csak 1 irhat-ja. A peldadban is, a vegeredmeny-ben 0 - 0-at fogsz kapni.

Ami nem atomic, hogy ebben az esetben a kiirataskor, mit latsz, mert az nyilvan el fog csuszni, hiszen az azon mulik, hogy epp mit olvas ki, viszont a valtozo mindenkori erteke az ebben az esetben atomic.

futtasd le:
public void run() {
for (int i = 1; i <= 30; ++i) {
if (getName().equals("t1")) {
k++;
} else {
k--;
}
System.out.println(getName() + ": " + k);
}
}

public int getK() {
return k;
}

main-ben sleep-ej picit run utan, amig veget nem ertnek a thread-ek, es irast ki a getK()-t es meglatod, mindket thread 0 -at mutat ra.

De lasd: http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html 8.3.1.4 volatile Fields
Es itt a Te peldad is: http://jeremymanson.blogspot.com/2007/08/volatile-does-not-mean-atomic.html

Szoval abban igazad, van, hogy a kiolvasas nem atomic, azaz nem feltetlen azt az erteket latod, amit elotte noveltel, viszont maga a k az atomic modosul, tehat nem hibazik.

Ergo ha szuksegunk van kozvetlen utana kiolvasni is ugyan azt az erteket, amire modositottuk, akkor kell syncronized , vagy ami meg jobb ebben az esetben az Atomic class-ok.

De a volatile-t legintkabb nem erre hasznalhatjuk, hanem thread safe flag-ekre. Egy thread beallitja, hogy true, akkor az ez utan lefuto masik thread mely ezt a valtozot akarja kiolvasni azt fogja latni, hogy true, es nem kell a draga koltsegu syncronized-ot hasznalni.
Előzmény: el Papi (5458)
el Papi Creative Commons License 2010.10.07 0 0 5462
Ugy hogy a counter-t private mezove teszed es enkapszulalod a modosito muveleteit.
Ezt akar egy synchronizalt getter-setter komboval is el lehet erni.
Előzmény: bigzed (5460)
angyalhentes Creative Commons License 2010.10.07 0 0 5461
Az eleje stimmel, a vége sajnos nem.

class SyncInt {
private final Object lock = new Object();
private int k;

public final void execute( SyncBlock block) {
synchronized( block ) {
k = block.syncExecute( k );
}
}

}

interface SyncBlock {
public int syncExecute( int currentValue );
}

Ez garantálja azt, hogy amíg a syncExecute() fut, addig senki nem piszkál hozzá k-hoz. A különböző műveleteid mind a SyncBlock implementációi lesznek, de ez nem okoz gondot, mert másképp nem lehet hozzáférni k értékéhez.

Erre persze csak akkor van szükség, ha előre nem látható számú megbízhatatlan műveleted lesz, egyébként a műveleteidet egyszerűen csak a SyncInt metódusaiként definiálod, és te magad garantálod azt, hogy a synchronized() blokk mindig jó helyen legyen.
Előzmény: bigzed (5459)

Ha kedveled azért, ha nem azért nyomj egy lájkot a Fórumért!