Jak odwołać się do jednego obiektu z dwóch wątków najszybciej jak się da?

Odpowiedz Nowy wątek
2015-02-01 15:41
0

Więc mam coś takiego

ConcurrentHashMap<InetAddress, Connection> connections = new ConcurrentHashMap<>();

Mam też wątek z ServerSocket który nasłuchuje na pakiety. Po adresie pakietu wyszukuję sobie Connection do której pakiet powinien polecieć i zostać przetworzony.

Chciałbym teraz zrobić nie tylko otrzymywanie i przetwarzanie pakietów, ale również odsyłanie informacji z powrotem do klientów. Najlepiej by było gdyby program mógł wysłać np 10-15 pakietów na sekundę w miarę równych odstępach czasu do każdego klienta.

Mógłbym skorzystać z intrinsic lock dla mapy connections ale wtedy przychodzące pakiety mogłyby na chwilę zablokować wątek odpowiedzialny za wysyłanie.

Są jakieś inne sposoby żeby osiągnąć mój cel? Czy ten jest w miarę ok?


edytowany 4x, ostatnio: TomRiddle, 2015-02-01 15:42
skąd masz taką rozległą wiedzę na temat programowania? Od kiedy programujesz? - Proxima Centauri 2015-02-15 21:50

Pozostało 580 znaków

2015-02-01 15:55
1

Chodzi o to że chcesz w sposób "bezpieczny" odczytywać te listę która może być modyfikowana z wielu miejsc ? no to bez synchronizacji się nie obejdzie, musisz się zabezpieczyć nie tylko przed niesynchronicznym dostępem(co w przypadku czytania nie jest szczególnie niebezpieczne) ale przez możliwością czytania danych które są już nieaktualne (stale data)


"Perhaps surprisingly, concurrent programming isn’t so much about threads or
locks, any more than civil engineering is about rivets and I-beams."
Możesz polecić jakiś tutorial/article? - TomRiddle 2015-02-01 15:57
concurrency in practice (ciekawa) i jeżeli taka concurency na szybko to tutorial oracla - ja jestem trochę retardem jeżeli o to chodzi, sam się dopiero uczę. - niezdecydowany 2015-02-01 16:16

Pozostało 580 znaków

2015-02-01 16:36
0

Ok, to zrobimy z synchronizacją. Do tego na Java™ Tutorials znalazłem fajną rzecz LinkedBlockingQueue<T>, użyję jej :D


Pozostało 580 znaków

2015-02-01 18:47
0

Jedno pytanko mam taki przykładowy kod

byte[] broadcastMessage;

public void zapisuje(byte[] bajty) {
  broadcastMessage = bajty;
}

public byte[] odczytuje() {
  return broadcastMessage;
}

odczytuje będzie wywoływane z kilku wątków, zapisuje z jednego. Chciałbym teraz żeby kilka wątków mogło odczytać coś jednocześnie, ale żeby żaden nie mógł odczytać kiedy się zapisuje.
Oczywistym jest więc żeby lock key obiektu broadcastMessage dostał zapisuje(), bo wtedy żaden wątek nie bd mógł odnieść się do obiektu:

byte[] broadcastMessage;

public void zapisuje(byte[] bajty) {
  synchronized (broadcastMessage) {
    broadcastMessage = bajty;
  }
}

public byte[] odczytuje() {
  return broadcastMessage;
}

Jednak nie jestem pewien czy to będzie dobre rozwiązanie. Nie mogę dać lock key obiektu broadcastMessage przy funkcji odczytuje bo wtedy tylko jeden wątek na raz będzie mógł z niej skorzystać.

Czy osiągnę w ten sposób spodziewany efekt?


edytowany 1x, ostatnio: TomRiddle, 2015-02-01 18:48

Pozostało 580 znaków

2015-02-01 19:04

To co zaklepałeś nie ma dla mnie sensu. Pamiętaj, że synchronized operuje na obiekcie, a nie na referencji. Stąd jeśli referencja się zmieni, to kolejne synchronized będzie działać na kolejnym obiekcie.

Być może twój problem może być rozwiązany przez: http://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
Więc jak powinienem napisać synchronized dla byte[] tak żeby jedna funkcja mogła z niego korzystać na raz? - TomRiddle 2015-02-01 19:07
Poza tym myślałem że byte[] = byte[] to przekazanie przez wartość :/ Muszę zrobić coś w stylu Array.copyOfRange() albo przelecieć pętlą i przypisać wartości? - TomRiddle 2015-02-01 19:09
System.arraycopy(). Ale jeżeli nie będzie w ogóle synchronizacji przy odczycie to będziesz mógł odczytywać podczas zapisywania. - Wibowit 2015-02-01 19:11
Dzięki za wyjaśnienie. Za to jeżeli będzie to nie będę mógł odczytywać z kilku miejsc na raz. Skorzystam z http://tutorials.jenkov.com/j[...]urrency/read-write-locks.html - TomRiddle 2015-02-01 19:22

Pozostało 580 znaków

2015-02-01 19:11
0

Tamto to było takie poglądowe przedstawienie tematu. Mój kod wygląda tak:

    final ArrayList<Element> broadcastMessage = new ArrayList<>();

    @Override
    public ArrayList<Element> getBroadcastMessage() 
    {
        return broadcastMessage;
    }

    public void setBroadcastMessage() {

        synchronized (broadcastMessage) 
        {
            broadcastMessage.clear();
            for (ConnectionToClient connection : elementList.values()) 
            {
                broadcastMessage.add(connection.getElement());
            }
        }
    }

ok, super, ale .... odczytujesz z miejsca które nie jest synchronizowane, te dane mogą być nieaktualne. - niezdecydowany 2015-02-01 19:35

Pozostało 580 znaków

2015-02-01 19:22
0

No to masz zły kod, bo może dojść do sytuacji w której jednocześnie odczytujesz i zapisujesz do kolekcji. Wystarczy, że jeden wątek odpali getBM i ją przegląda, a drugi odpali setBM.

Możesz spróbować użyć ReadWriteLock. Ewentualnie, jeżeli np modyfikacje kolekcji są bardzo rzadkie to możesz np użyć niemutowalnej Listy, opakować referencję do Listy w AtomicReference, a w set użyć AtomicReference.compareAndSwap w pętli. Tzn wyglądałoby to tak:

AtomicReference<List<Element>> kolekcja = ???;

get() {
  return kolekcja.get();
}

set() {
  List<Element> snapshot;
  do {
    snapshot = kolekcja.get();
    List<Element> nowa = ???;
    // tutaj wypełniamy listę nowa, ale nie modyfikujemy starej (czyli snapshota)
  } while (!kolekcja.compareAndSet(snapshot, Collections.unmodifiableList(nowa)));
}

"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 3x, ostatnio: Wibowit, 2015-02-01 19:23
Modyfikacje będą ~ 10-20 razy na sekundę. - TomRiddle 2015-02-01 19:26

Pozostało 580 znaków

2015-02-01 19:28
0

A gdybym powiedział walić to i niech te odczyty będą po kolei, a nie na raz to wtedy taki kod będzie ok?

final ArrayList<Element> broadcastMessage = new ArrayList<>();

    @Override
    public ArrayList<Element> getBroadcastMessage() 
    {
        synchronized (broadcastMessage) {
            return broadcastMessage;
        }
    }

    public void setBroadcastMessage() {

        synchronized (broadcastMessage) 
        {
            broadcastMessage.clear();
            for (ConnectionToClient connection : elementList.values()) 
            {
                broadcastMessage.add(connection.getElement());
            }
        }
    }

edytowany 1x, ostatnio: TomRiddle, 2015-02-01 19:28
odczyt i zapis jest synchronizowany więc ok. - niezdecydowany 2015-02-01 19:36

Pozostało 580 znaków

2015-02-01 19:31
0

@TomRiddle a co jak ktoś dostanie tą referencje i będzie sobie chciał iterować po liście a drugi wątek stuknie clear? ;)


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2015-02-01 19:34
0

@Shalom dopiszę private przed deklaracją :D

A tak serio to nie wiem.

PS: AAaaa, już wiem. O to chodzi?

return broadcastMessage;
return new ArrayList<>(broadcastMessage);

edytowany 5x, ostatnio: TomRiddle, 2015-02-01 19:36

Pozostało 580 znaków

2015-02-01 19:36
1

A no widzisz ;] Bo jak robisz takie rzeczy to musisz synchronizować każdy dostęp do elementów listy a nie tylko sam fakt otrzymania referencji ;]

edit: No tak, możesz zrobić kopię, to jakieś rozwiązanie, przynajmniej o ile elementy tych kolekcji są immutable.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
edytowany 1x, ostatnio: Shalom, 2015-02-01 19:36
To jest ok rozwiązanie? Czy raczej takie na odwal sie. - TomRiddle 2015-02-01 19:37

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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