Po co wait i notify w każdym obiekcie?

0

Tak sobie myślę, że te metody pociągają ze sobą automatycznie jakiś stan, który jest sporym obciążeniem dla prostych obiektów (tak z kilka bajtów na każdy obiekt do trzymania informacji do synchronizacji).

Gdyby tak zrobić klasę wbudowaną np Semaphore extends Object, o funkcjonalności obecnego Objectu, a nowy Object byłby całkowicie pozbawiony wait i notify to może poprawiłoby to wydajność.

W zasadzie, to jeżeli moje powyższe przemyślenia nie mijają się z prawdą, to wtedy ArrayList<OgołoconyIntegerBezWaitINotify> miałoby taką samą wydajność i zajętość pamięci jak int[] (zakładając że JVM byłby w stanie zastąpić tablicę referencji do obiektów przez tablicę tych obiektów, oczywiście pod warunkiem że stanem tego obiektu byłyby same typy prymitywne). To doprowadziłoby do sytuacji kiedy Integer miałby taką samą wydajność jak int i nie trzeba byłoby w ogóle udostępniać intów.

0

Pamiętaj, że każdy obiekt musi mieć referencję na tablicę swoich metod wirtualnych.
Gdyby więc wait/notify nie istniało, to nadal int != Integer.

0

Integer jest klasą final, więc odpada tablica metod wirtualnych.

0

Przy designie Javy po prostu chcieli aby kazdy object byl 'monitorem' (dokladniej sa to monitory Mesa), dlatego tak zrobili. Teraz juz za pozno na zmiany, nawet jesli to co mowisz ma sens (nie zaglebiam sie).

0

To może inaczej zapytam:
Czy gdybym budował własną VM to czy wait i notify w każdym obiekcie ma jakąś potężną zaletę, która jest tak duża, że przewyższa wspomniane przeze mnie wady (a są one poważne)?

0

Opowiadasz. Narzut Object jest 8 bajtów. 4 bajty na wskaźnik na vtable i 4 bajty na wszystko inne. Zauważ, że wszystkie obiekty muszą mieć też miejsce na flagi używane przez GC. Więc i tak w mniej niż 8 bajtach zamknąć się tego nie da. Istnieje coś takiego jak object-inlining, który redukuje nieco narzut, ale to jest na razie research.

0

W obiektach klas final nie trzeba wskaźnika do vtable. Przy obiektach nie mających referencji do innych obiektów (ma tylko jedno pole prymitywne) też nie trzeba mieć chyba żadnych flag. Taki obiekt można odwiedzić jeśli nie jest nullem, a skoro w środku nic nie ma to nie ma sensu go odwiedzać. W zasadzie zostawałby tylko bit oznaczający czy ten Integer jest nullem, a jeden bit to niedużo. Tym samym narzut na Integera zostałby zmniejszony do jednego bita (+ padding do iluś tam bajtów - biorąc pod uwagę to że w danej klasie można mieć kilka pól typu Integer to te bity można sklastrować).

Chodzi mi przede wszystkim o klasy typu Integer, Float, Double, etc. Mają jedno pole prymitywne, są typu final, a więc idealni kandydaci do optymalizacji.

0

Przeczytaj sobie TIJ4. Tam jest dokładnie wyjaśnione (chyba w rozdziale Concurrency) dlaczego każdy bez wyjątku obiekt musi mieć wait i notify oraz jak duże zalety ma umieszczenie ich w korzeniu hierarchii klas.

ps. A co do klas final, to pamiętaj, że każda taka klasa jest kandydatem do zdjęcia final (były już takie przypadki), natomiast żadnej klasie, która nie była finalna nie da się już w przyszłości założyć tego modyfikatora bez utraty zgodności ze wcześniejszymi wersjami. A jak wiadomo to ostatnie nie przejdzie.

0

Znalazłem coś takiego:

One fairly unique aspect of wait( ), notify( ), and notifyAll( ) is that these methods are
part of the base class Object and not part of Thread. Although this seems a bit strange at
first—to have something that’s exclusively for threading as part of the universal base class—
it’s essential because these methods manipulate the lock that’s also part of every object. As a
result, you can put a wait( ) inside any synchronized method, regardless of whether that
class extends Thread or implements Runnable. In fact, the only place you can call wait( ),
notify( ), or notifyAll( ) is within a synchronized method or block (sleep( ) can be
called within non-synchronized methods since it doesn’t manipulate the lock). If you call
any of these within a method that’s not synchronized, the program will compile, but when
you run it, you’ll get an IllegalMonitorStateException with the somewhat nonintuitive
message "current thread not owner." This message means that the task calling wait( ),
notify( ), or notifyAll( ) must "own" (acquire) the lock for the object before it can call any
of those methods.

Nadal nie rozumiem dlaczego wait() i notify() muszą się znajdować w każdym obiekcie. Przecież można zrobić klasę wbudowaną z lockami dziedziczącą po nielockowalnym Objekcie. I np pisząc swoją klasę dziedziczącą po nielockowalej innej klasie której nie mogę zmienić, mógłbym dołożyć jakieś pole dziedziczące lub będące semaforem (ew. muteksem) i dobierać się do jego locka.

Jak jest z tym w .NET?

Albo wie ktoś jak wypada porównanie z synchronizacją w GPGPU? Tam jest duuuuuużo wątków, więc synchronizacja jest pewnie zrobiona z najmniejszym kosztem wydajnościowym.

0

Nawet z tego tekstu to wynika. Specyfikacja języka wymusza możliwość założenia bloku synchronizowanego (lub metody) dla każdego możliwego obiektu.
Gdyby wait i notify nie występowały w każdym obiekcie, to metody i bloki synchronizowane nie mogłyby być ogólną własnością języka Java lub taka "synchronizacja" nie miałaby żadnego znaczenia praktycznego.

0

IMHO z tego tekstu wynika jedynie ze kazdy obiekt jest monitorem tylko i wylacznie dlatego zeby bylo mozna pisac metody synchronizowane:
public synchronized void method() {...

Gdyby bylo jak chce Donek to by to bylo niemozliwe, dzialalyby tylko bloki:
public void method() {
synchronized (mutex) {... // gdzie mutex jest obiektem klasy Mutex czy jak ja tam Donek nazwal

Wydaje mi sie ze zrobili to po to, ze Java byla reklamowana jako prosciutki jezyk. Chesz odpornosc na watki? Nic prostszego, dodaj do metody synchronized i juz! Bez potrzeby jawnych mutexow czy innych. To jedyny sens jaki w tym widze, i jak juz napisalem, taka zmiana jaka proponuje Donek nie moze miec miejsca i juz. Ale sam pomysl wydaje mi sie calkiem sensowny, sam sie nieraz nad tym glowilem ale stwierdzilem ze madrzejsi ode mne to wymyslali. Teraz widze ze nie jestem sam ;d

.NET:
synchronizowana metoda: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions.aspx
oraz block lock ktory wymaga jawnego obiektu, zupelnie jak blok synchronized w javie.

0

Cytat z artykulu: http://blogs.epfl.ch/document/24460

Fundamentally, the two mechanisms that are expected from a concurrency control model are
isolation and signaling. Isolation requires that operations in concurrent processes cannot access the data
in an intermediate (and probably inconsistent) state while an operation is being done. Signaling is the
mechanism that a process uses to inform a waiting process of an event. Signaling can be implemented
using the isolation abstraction but in a polling (i.e. busy waiting) and not interrupting form. To have an
efficient implementation of signaling, scheduler should be engaged and not schedule waiting processes
until they are signaled. That is why signaling is supported in Java Object class besides locks. As signaling
cannot be efficiently implemented by the isolation abstraction, it should be a first class feature and be
implemented on the basic signaling mechanisms of the underlying (virtual) machine.

Bycmoze chodzi o mechanizmy typu GC, aby mogly optymalizowac swoje dzialanie. Poza tym, moze to byc uklon w strone projektantow JVM, ktorzy dostaja spojny interfejs, na podstawie ktorego moga realizowac zarzadzanie watkami.

1 użytkowników online, w tym zalogowanych: 0, gości: 1