Wielowątkowość w Javie - synchronizacja

0

Witam wszystkich! Pisząc swoje programy w javie natknąłem się na problem współbieżności jego wykonywania. Chciałbym napisać aplikację która będzie wykorzystywać jedną bazę danych, ale oparta będzie na wielu wątkach. Pytanie do Was jest następujące: czy możliwe jest tak zsynchronizować to zadanie aby działało to sensownie szybko? Obecnie z moich testów wynika iż przy utworzeniu 4 wątków owszem program pracuje około 4 razy szybciej(mam 4 rdzeniowy procesor), ale dopóki nie dodam bloków synchronized przy dodawaniu i pobieraniu z bazy danych(bez bloków w bazie jest bałagan i nie służy ona do niczego). Nadmienię, jedyną przeszkadzającą mi rzeczą jest problem dodawania do bazy, gdyż jeżeli dana jest już w bazie każdy wątek ma swój obszar roboczy w pamięci na czym może działać - zatem problemem jest tylko i wyłącznie dodawanie...

Gdy próbuje coś dodać:
sprawdzam czy to jest w bazie jeżeli jest nic nie robię
jeżeli nie ma - dodaje

Problem pojawia się wtedy gdy dwa wątki będą chciały dodać to samo, bo jeden nadpisze drugi i utracę część danych...

Mam nadzieje że wyjaśniłem w miarę sensownie mój problem i zdołacie koledzy mi pomóc

Dziękuję za odpowiedzi
Pozdrawiam
Kamil

0

A co to za baza danych? Przecież normalne SZBD mają poziomy izolacji transakcji oraz constrainty które powinny te wszystkie twoje problemy rozwiązywać samodzielnie.

0

Bazę danych tworzę na podstawie plików, zasysając je do pamięci... problem jest przy tworzeniu tej bazy danych...
Baza danych w tym przypadku to sensownie poukładana pamięć...

0

To może w takim razie warto użyć normalnej bazy danych?

0

Proponuję użyć odpowiedniego narzędzia do problemu. Będzie to albo standardowa baza danych, albo Clojure.

Twój problem polega na tym, że właściwie chcąc napisać coś w standardowej Javie musisz wynaleźć od zera silnik bazy danych.

Bazy danych takie jak PostgreSQL, Oracle, MySQL, Firebird... używają modelu pamięci transakcyjnej z zaimplementowanym MVCC (multiversion concurrency control). Mniej więcej na oko napiszę, że taka konstrukcja pozwala modyfikować dane w pamięci (bazę) i jednocześnie mieć możliwość jej odczytu. MVCC umożliwia zrobienie snapshota stanu takiej bazy, którego spokojnie zapisujesz do pliku nawet w czasie działania programu i żadne dane nie będą niespójne. Snapshot nie zatrzymuje działania programu, dostajesz jedynie dane, które były w momencie jego tworzenia.

Język Clojure jako jeden z nielicznych, a w zasadzie jedyny z posiada zaimplementowany model pamięci transakcyjnej z MVCC i możliwość trywialnego utworzenia bazy, o której piszesz w pamięci bez mordęgi związanej z wątkami w Javie. Inne języki implementują STM przez biblioteki,

Dokładnie o tym problemie, czyli to, co cię interesuje jest w 1h 7min w tym filmie:

Polecam : http://blip.tv/clojure/clojure-concurrency-819147

Jeżeli jednak chcesz się trzymać Javy to masz to: http://multiverse.codehaus.org/60second.html , ale tutaj jesteś zupełnie sam.

0

Możesz poczytać o "problemie czytelników i pisarzy", choć nie jestem w 100% czy pasuje w Twoim przypadku. Jeśli pasuje, to najłatwiej będzie synchronizować dostęp do chronionych zasobów używając ReentrantReadWriteLock.

Jakie w Twoim programie jest źródło danych do przetworzenia? Jeśli dane są w jakiś sposób generowane, a następnie przetwarzane, to możesz pomyśleć o producencie i konsumencie - czyli jeden wątek generuje dane do przetworzenia (odczytuje z pliku, sieci, bazy, cokolwiek) a następnie przekazuje do drugiego, który je przetwarza. Potem może być kolejny, który np. zapisze wyniki. Architektura jest prosta, ale obsługa błędów może być dość skomplikowana. W Javie łatwa realizacja przy użyciu kolejki synchronizowanej, BlockingQueue. Oczywiście możesz mieć wiele wątków producentów i konsumentów.

No i można pomyśleć nad rozbiciem zadania na odpowiednio mniejsze i wykonywaniu przez Executora.

To tak w ostrym skrócie... ;-)

kamilbedik napisał(a):

Witam wszystkich! Pisząc swoje programy w javie natknąłem się na problem współbieżności jego wykonywania. Chciałbym napisać aplikację która będzie wykorzystywać jedną bazę danych, ale oparta będzie na wielu wątkach. Pytanie do Was jest następujące: czy możliwe jest tak zsynchronizować to zadanie aby działało to sensownie szybko? Obecnie z moich testów wynika iż przy utworzeniu 4 wątków owszem program pracuje około 4 razy szybciej(mam 4 rdzeniowy procesor), ale dopóki nie dodam bloków synchronized przy dodawaniu i pobieraniu z bazy danych(bez bloków w bazie jest bałagan i nie służy ona do niczego). Nadmienię, jedyną przeszkadzającą mi rzeczą jest problem dodawania do bazy, gdyż jeżeli dana jest już w bazie każdy wątek ma swój obszar roboczy w pamięci na czym może działać - zatem problemem jest tylko i wyłącznie dodawanie...

Gdy próbuje coś dodać:
sprawdzam czy to jest w bazie jeżeli jest nic nie robię
jeżeli nie ma - dodaje

Problem pojawia się wtedy gdy dwa wątki będą chciały dodać to samo, bo jeden nadpisze drugi i utracę część danych...

Mam nadzieje że wyjaśniłem w miarę sensownie mój problem i zdołacie koledzy mi pomóc

Dziękuję za odpowiedzi
Pozdrawiam
Kamil

0

Masz tu przykład prosty jak but jak zrealizować po części to, co chcesz:


(def tabela (ref []))

(defn dodaj_wiersz [tabela wiersz]
  (dosync (commute tabela conj wiersz)))

(defn usun_wiersz [tabela numer]
  (dosync (if (and (>= (count @tabela) numer)
                   (>= numer 0))
              (ref-set tabela (concat (take (dec numer) @tabela) 
                                (nthrest @tabela numer)))
              @tabela)))

(defn usun_wiersze [tabela filtr]
  (dosync (ref-set tabela (remove filtr @tabela))))

;ex:

@tabela
-> []

(dodaj_wiersz tabela [1 2 3])
-> ([1 2 3])

(dodaj_wiersz tabela [2 3 4])
-> ([2 3 4] [1 2 3])

(dodaj_wiersz tabela [3 4 5])
-> ([3 4 5] [2 3 4] [1 2 3])

(usun_wiersz tabela 2)
-> ([3 4 5] [1 2 3])

@tabela
-> ([3 4 5] [1 2 3])

(dodaj_wiersz tabela [1 3 3])
-> ([1 3 3] [3 4 5] [1 2 3])

(usun_wiersze tabela #(= (first %) 1)) ; - usun jezeli perwszy element wiersza = 1
-> ([3 4 5])

To wszystko bez locków i innych cudów.
Przy czym cały czas masz dostęp do spójnych danych tabeli poprzez @tabela, które możesz śmiało zapisać na dysku.

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