Lista Stron

Streszczenie


Protokół komunikacji między serwerem a klientem w doświadczeniu Comptona dla ilf

Protokół komunikacji między serwerem a klientem w doświadczeniu Comptona dla ilf

TODO

data: 15 Dec 2009 13:01 tagi: compton ilf protocol


Compton@ilf

Webowa część eksperymentu Comptona

Architektura:

Achitektura jest dość złożona…

Całość komunikuje się po protokole podobnym do XMPP (nie wiem czy zgodne ze standardem …).

Hermes
Mamy klienta, aplikację Java Web Start, która pełni rolę kilenta XMPP.
Zeus
Rolę serwera XMPP pełni zeus.
Serwery eksperymentów
Też są klienami w sensie Jabbera. Zeus łączy się do nich jak jakiś klient startuje eksperyment. Serwery są sterowane wiadomościami XMPP i w ten sam sposób wysyłają wyniki.

Protokuł komunikacji

Protokół komunikacji

Eksperyment Comptona w internetowym labie Fizyki udostępniać będzie przeprowadzanie eksperymentu comptonam każdemu zarejestrowanemu użytkownikowi laboratorium p.

data: 15 Dec 2009 12:48 tagi: compton ifpw ilf


Experyment Comptona

Oprogramowanie eksperymentu comptona

Generalnie program jest w kilku wersjach

  • offline bezpośrednio pobierającej dane ze sprzętu.
  • offline pracującej na zapisanych danych (program pozwala na prostą analiże zebranych danych) w projekcie
  • online działającej jako część internetowego laboratorium fizyki (będzie niedługo działać :))

Moja praca inżynierska skończona prawie. Jak złożę wrzucę tutaj pliki programów i samą pracę.

data: 15 Dec 2009 12:29 tagi: compton ifpw


Zarlock

Żarłok

v 1.0

Żarłok to aplikacja która zarządza magazynem żywnościowym na obozie harcerskim i generuje zmorę komendantów ZHP — czyli dokumentację żywnościową. Napisałem ją dobre dwa lata temu i pisanie jej zajęło mi jakiś miesiąc. krótka historia żarłoka

v 2.0

A że dwa lata to szmat czasu zarówno na rynku oprogramowania (nowe narzędzia!) jak i dla mnie, postanowiłem od zera napisać drugą wersję.

Wersja do ściągnięcia

Pliki: są tutaj

Program potrzebuje oprogramowania JAVA (w wersji 1.6) dostępnego z http://www.java.com/pl/download/index.jsp.

Metoda uruchomienia:

Rozpakować archiwum, a następnie kliknąć dwa razy na odpowiednio zarlock.bat(windows), albo zarlock.sh(linux).

Cele aplikacji

Głównym celem tego programu jest maksymalne zmniejszenie pracochłonności utrzymywania bierzącej dokumentacji żywnościowej.

Szczegółowo

  • Przegenerowanie całej dokumentacji żywnościowej ma wymagać jednego kliknięcia!

Otwarte problemy i pytania

Znajdują się tutaj wszystkie nierozstrzygnięte jeszcze kwestie dotyczące żarłoka 2.0.

Projekt do zarządzania magazynem żywnościowym na obozie harcerskim. Powstały jego dwie wersjie, a trzecia jest w toku :)

data: 15 Dec 2009 12:15 tagi: zarlock zhp


Debug Hangs X

O tym jak zwiesić serwer Xów (graficzne GUI linuxa) za pomocą debuggera Javy. I co ważniejsze —- jak tego nie robić.

Zdarza się czasem że Xy wieszają się podczas debugowania kodu javy, dokładnie wtedy kiedy breakpoint jest ustawiony w kodzie który jest wykonywany podczas wyświetlania dowolnego popupa (na przykład popupa comboboxa).

Rozwiązaniem jest podanie aplikacji debugowanej parametru: -Dsun.awt.disablegrab=true.

Źródło: BUG #6714678.

data: 13 Dec 2009 23:05 tagi: debug linux swing xserver


Swing Compiz

Rozwiązanie problemów z aplikacjami Javy wynikających z używania Comipza.

Jeśli ma się używa compiza to aplikacje swingowe mogą nie działać — w ogóle nie malują się ramki.

Można to rozwiązać ustawiając przed odpaleniem javy zmienną środowiskową AWT_TOOLKIT na wartość MToolkit.

czyli starczy linijka

export AWT_TOOLKIT="MToolkit"

Developer

Wrzuć to do skryptu startowego swojej aplikacji.

User

Wrzucić gdzieś gdzie będzie odpalane przy starcie X-ów /etc/profile, ~/.profile.

Więcej na forum Ubuntu

data: 13 Dec 2009 23:03 tagi: beryl compiz java linux swing


Lazy Initialization Exception

LazyInitializationException jako wynik bugu w encji

To make a long story short. Używałem seamowego frameworku z obiektami home, no i w obiekcie home musiałem przepakować jakąś kolekcję. No i na pierwszym wywołaniu metody na kolekcji encji rzucało LazyInitializationException.

Bug był taki że w klasie encji nie inicjalizowałem pustej kolekcji.

Było:

@OneToMany() 
@MapKey(name="semestr")
Map<String, SemestrPlanStudiowMapper> semestrPlanStodiow;

Powinno być:

@OneToMany() 
@MapKey(name="semestr")
Map<String, SemestrPlanStudiowMapper> semestrPlanStodiow = new HashMap<String, SemestrPlanStudiowMapper>();

data: 13 Dec 2009 23:01 tagi: hibernate jee lazyinitializationexception


Rendered Richfaces A Jsf

Czyli o zachowaniu atrybutu rendered w jsf

Wyobraźmy sobie taką stronę.

<a:commandButton action="..." reRender="foo"/>
<!--...-->
<rich:outputPanel id="foo" rendered="#{...}"/>

Ten kod nie działa jeśli panel nie jest na początku zrenderowany. RichFaces po naciśnięciu guzika przerenderowuje panel, i wysyła go na stronę ale po stronie klienta nie wiadomo gdzie go wstawić na stronie. Jeśli jakiś tag ma rendered="false" to jest on całkowicie usuwany ze strony tak że nie ma nawet markera 'tu powinien być panel taki a taki'.

Żeby ta strona działała trzeba komponent mający rendered="false" opakować w <a:outputPanel layout="none" ajaxRendered="true">1 czyli powinno być tak:

<a:commandButton action="..." reRender="foo"/>
<!--...-->
<a:outputPanel layout="none" ajaxRendered="true">
    <rich:outputPanel id="foo" rendered="#{...}"/>
</a:outputPanel>

Output Panel ma dwie funkcje:

  1. Powoduje że jego zawartość jest renderowana ponownie zawsze przy każdym requeście ajaksowym
  2. Jeśli jakieś jego dziecko nie jest renderowane wstawia zamiast niego markera, który umożliwi wstawienie go później.

data: 13 Dec 2009 22:59 tagi:


Pattern A Sprawa Polska

Czyli jak zmusić patterny żeby 'łapały' polskie znaki

Szybka notka:

Wzorzec zdefiniowany przez java.util.Pattern jest gotowy na przyjęcie Polskich znaków, natomiast nie wszystkie predefiniowane klasy akceptują je.

W szczególności \w, określana jako word character nie machuje polskich znaków.

czyli:

    "ą".matches("\\w") == false

Klasą przyjmującą znaki słów spoza bloku ASCII jest \p{L}.

Jakby ktoś chciał poczytać dokładniej to niech poczyta:

data: 13 Dec 2009 22:56 tagi: internacjonalizacja regexp


Mysql Hibernate I Polskie Znaki

Czyli co może się zepsuć przy używaniu mysqla razem z hibernatem i generowaniem tabelek

Hibernate jest mądry i fajny, ale nie aż tak żeby tworzył kolumny w których kodowaniem znaków jest przyjmujące polskie znaki. Przy tworzeniu bazy danych hibernate nie specyfikuje kodowania i porządku1 typach VARCHAR. Wtedy dane te są pobierane z wartości domyślnych tabeli, które też nie są przez Hibernata specyfikowane, i pobierane są z wartości domyślnych bazy danych, które są specyfikowane bóg-wie-gdzie.

Czyli defaulty wyglądają tak:

  1. kodowanie kolumny
  2. kodowanie tabeli
  3. kodowanie schematu
  4. kodowanie mysql

U mnie kodowanie mysql2 domyślnie ustawione jest cp1252. Czyli nie ma polskich znaków …

Jedynym rozwiązaniem jest przy tworzeniu schematu ustawić mu ręcznie CHARSET i COLLATION.

Z podręcznika MySQL

CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
    [create_specification] ...
 
create_specification:
    [DEFAULT] CHARACTER SET [=] charset_name
  | [DEFAULT] COLLATE [=] collation_name

Czyli u nas jakoś tak:

    CREATE DATABASE CHARACTER SET = utf8

Będziemy używać utf-a żeby nie musieć pisać użytkownikowi: 'pana imie nie może zawierać e z akcentem'.

A co jeśli chcę zmienić kodowanie w bazie która istnieje.

Pewno da się jakimś skryptem… Ale ja jestem dzieckiem neostrady i po to używam Hibernejta żeby nie umieć SQLa.

To robimy tak. W gui MySQL (mysqladmin) robiy backup bazy danych zaznaczając opcję NO CREATES3.

Dropujemy bazę dancyh.

Tworzymy nową z ustawionym kodowaniem.

Odpalamy jeszcze raz Hibernejta (z opcją tworzenia schematyu danych) — mamy już tabelki.

Za pomocą linii komend mysqla (mysql) wywołujemy polecenie source [ścieżka do pliku z backupem] — co zaimportuje dane

data: 13 Dec 2009 22:55 tagi: hibernate jee mysql


Maven Encoding

Ustawienie kodowania plików tekstowych.

Inaczej Maven weźmie kodowanie domyślne dla platformy

pliki resources:

<project . . . >
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

Pliki źródłowe:

<project . . . >
 <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

data: 13 Dec 2009 22:52 tagi: maven pom


Maven Src Directory

Zmiana położenia katalogu ze źródłami

<project . . . >
   <build>
        <sourceDirectory>src</sourceDirectory>
    </build>

data: 13 Dec 2009 22:51 tagi: maven pom


Maven Repozytoria

Dodawanie kolejnych repozytoriów

Troszkę boję się dodawać wygooglane repozytoria, ale w głównym często nie ma tego co tygryski-lubią-najbardziej:

<project . . . >
   <repositories>
        <repository>
            <id>jboss-repo</id>
            <url>http://repository.jboss.com/maven2/</url>
        </repository>
        <repository>
            <id>ibidio</id>
            <url>http://www.ibiblio.org/maven2</url>
        </repository>
    </repositories>

data: 13 Dec 2009 22:50 tagi:


Maven Poziom Jezyka

Ustawienie poziomu języka

<project . . . >
   <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

data: 13 Dec 2009 22:49 tagi: maven pom


Maven All

Wszystkie artykuły o pliku POM mavena

The ListPages module does not work recursively.

data: 13 Dec 2009 22:47 tagi: maven pom


Jak Pisac Programy

Jak pisać programy?

Po długich bojach doszedłem że mniej więcej tak powinien wyglądać cykl deweloperki kawałka aplikacji. Kawałka czyli jakiejś funkcjonalności, klasy. Ogólnie ma być to na tyle nieskomplikowane żeby dało się to objąć umysłem na raz.

  1. Wiedzenie co kod ma robić. Wiedza ta może przybrać formę specyfikacji, ale nie musi — to ty musisz wiedzieć co piszesz
  2. Pisanie kodu
  3. Pisanie testów. I testowanie.
  4. Usunięcie wszystkich warningów
  5. Przelecenie się FindBugiem po kodzie. To takie fajne narzędzie pozwalające wykryć dziwne ciężko testowalne bugi (w stylu nie zamknięcie OutputStreama).
  6. Poprawki kodu tak żeby findbug nie dawał errorów.
  7. Pisanie dokumentacji.

Ja wiem że są ludzie którzy by to odwrócili — 'najpierw napisz testy', 'jak nie jesteś w stanie napisać testów, to znaczy że niedostatecznie wyspecyfikowałeś aplikację', 'najpierw specyfikacja API'.

Ale ja nie jestem dobry na tyle żeby z powietrza tak wyspecyfikować program żebym najpierw pisał dokumentację, a potem implementację. Co więcej kiedy mam pracujący kod mogę łatwo go ulepszać i wychodzi (moim zdaniem) lepszy niż to co wymyślałem na początku.

Idea jest taka że w każdym kroku możesz zmieniać to co powstało w krokach poprzednich - pisząc testy (jak znajdziesz buga) zmieniasz kod, tak samo jak usuwasz warningi. Odwrócenie tego powoduje zwiększoną ilość pracy — jeśli masz dokumentację, testy i kod bez warningów i coś zmieniasz w nim to trzeba zmienić i testy i dokumentacjię i … .

data: 13 Dec 2009 22:43 tagi: argumentative


Swing Internatonalize

Internalizacja komponentów swinga

Notka dotyczy internacjonalizacji komponentów swinga, takich jak JFileChooser, JOptionPane i tak dalej, a nie całej aplikacji swingowej.

Nie ma dobrej metody na internacjonalizacje komponentów swinga, większość jest w jakiś sposób zła, niektóre są jednak mniej złe od innych.

Natywne Look and Feele które powinny wyświelać natwne komponenty prawodopodobnie używają locale systemowego i będą działać same. Natomiast Look and Feele Javy (metal, nimbus) pobierają napisy z UIDefaults. Rzeczywiście w UIDefaults są klucze takie jak FileChooser.cancelButtonText=Cancel.

Rozwiązanie złe

Pierwszym rozwiązaniem jest więc po prostu zrobienie czegoś takiego:

    UIManager.put("FileChooser.cancelButtonText", "Anuluj");

jednak dla mnie jest to rozwiązanie złe z kilku powodów głównie z tego powodu że gdzieś w inicjalizacji programu muszę pamiętać zeby te klucze ustawić i muszę je ustawiać zawsze po zmianie Look and Feela. Co więcej po czymś takim program będzie miał na sztywno ustawione jedno locale, to znaczy bez względu na locale systemowe standardowe komponenty swinga są po polsku. Oczywiście można by to costumizować żeby jeśli locale to pl_PL ustawiać te klucze w UIManagerze, a jeśli fr_FR to nie. Ale to już jest komplikowanie sobie życia…

Rozwiązanie w złe, ale lepsze niż poprzednie

Trzeba więc poszperać dalej. Poszperałem dalej na własną rękę i znalazłem w standardowej dystrybucji javy następujące paczki:

paczki-lokalizacja.png

Wyglądają one łudząco podobnie do normalnego ResourceBoundla który służy do internacjonalizacji. Starczy do tej paczki dodać ResourceBoundla z polskimi napisami i nasz progam automagicznie będzie miał dobre Locale :).

Dodam że starczy w tej paczce umieścić plik metal_pl.properties1, a automagicznei powstanie z niego resource bundle.

Wszystkie klucze z lokalizacją są w (nieprzetłumaczonym jeszcze) pliku metal_pl.properties.

No i wreszcie — jak umieścić ten plik w paczce (bądź co bądź) com.sun.*, czy trzeba rozpakowywać jary JRE. Otóż wcale niekoniecznie, starczy stworzyć taką paczkę w twoim jarze, w którym jest Twój program a JRE już sobie odpowiednie pliki znajdzie :).]

PS. A dlaczego jest to rozwiązanie złe? Głownie dlatego że jednak grzebie się w klasach com.sun.*, które moga się zmieniać nie tylko z wersji na wersje Javy, ale wręcz mogą zmieniać wraz z updejtami, updejtami bezpieczestwa i tak dalej.

A co z nimbusem

Wydaje mi się że Nimbus jest automagicznie naprawiony kiedy naprawimy Metala. Rzut oka na klasy z JRE i widzimy że Nimbus dziedziczy po Metalu.

data: 13 Dec 2009 22:41 tagi: internacjonalizacja swing


Java Concurrency

Model wielowątkowości i pamięci Javy. Co to jest, jak używać.

Ogólnie

Zakładam że czytelnik wie co to jest wielowątkowść ogólnie. Jak nie wie niech przeczyta rozdział 13 'Thinking in Java' tu (patrzlinki).

Model wielowątkowości

Model wielowątkowości

Co możemy z tym zrobić:

Synchronizacja

JVM daje gwarancje że tylko jeden z bloków synchronizowanych na kluczu A będzie wykonywany na raz.
Ponadto wątki muszą synchronizować swoją pamięć z pamięcią główną kiedy zdowbywają klucz.
Kompilator może przestawiać kolejność wykonywania poleceń. Ale nie może przenieść poleceń z bloków synchronizowanych poza nie.
Nie gwarantuje to:
Kolejności wykonywania metod.

volatile

Jeśli zmienna jest volatile to wątki nie mogą wykonywać kopii jej z pamięci głównej do swojego kasza.

immutable

Jeśli zmienna jest immutable to (czyli jej stan się nie zmienia) to dowolna ilość wątków może z niej czytać.

Atomowość

Jeśli jakaś operacja jest atomowa oznacza to że jej wykonanie jest de facto jedną instrukcją procesora, czyli nie ma ona stanu pośredniego który może się spsuć.
Jednak
W Javie nie ma operacji atomoych poza java.util.concurrent.atomic. Nawet:

    i++;

nie jest atomowe. Szczególnie jeśli i to long, ale dla intów też nie daje rady.

Synchroniacja:

Jak się synchronizuje to każdy wie (zresztą nie wgryzłem się jeszcze w nowy framework do wielowątkowości z JDK6…, a staroci nie będę publikował!) Polecam zaznajomić się z java.util.concurrent, atomic, lock.

Ważne jest to czego synchronizacja nie gwarantuje:

Wady synchronizacji

Nie gwarantuje kolejności wykonywania funkcji.

Przykład niezsynchronizowany

Przykładowo:

class Sample {
 
    int a = 1, b = 2;
    void hither() {
        a = b;
    }
    void yon() {
        b = a;
    }
}

W klasie wątek A woła jedną metodę Sample wątek B drugą.

Wynikiem może być:

  • Zamiana wartości a i b.
  • a = b = 2 lub a = b = 1

Oraz może być tak że wątki A i B mają w swoich keszach niezgodne wartości np: A uważa że a = 1 a B uważa że a = 2.

Przykład zsynchronizowany

Jeśli metody zsynchrnonizumejy to możliwe będą tylko dwa wyniki:

  • a = b = 2 lub a = b = 1

Oraz wątki będą się zgadzały do do tego która możliwość zaszła.

Dokładniejsze analizy w [3].

Kolekcje

Problem:
Mamy w programie kolekcję z której niektóre wątki sobie czytają a inne do niej piszą1. Problem polega na tym że co jakiś czas leci ConcurrentModificationException.

Nie rozwiązanie
Rozwiązaniem nie jest synchronizacja kolekcji (z użyciem Collections.synchronizedXXX()).

** O co chodzi**
Ogólnie kolekcje mają mechanizm który powoduje że nie da się ich modyfikować strukturalnie i czytać w tej samej chwili. Mechnizm ten nie jest mechanizmem pewnym, raczej jest to best effort. I dotyczy on nie tyle operacji na samej kolekcji ale na jej widokach (i iteratorach) i powoduje rzucenie wyjątku jeśli z jakiegoś widoku czyta się dane które zostały zmodyfikowane za pomocą innego widoku (nawet w jednym wątku).

Czyli jeśli wątek A woła:

    map.get("foo");

Natomiast wątek B:

    map.remove("foo");

Wszystko jest cacy. Od kolejności wywołania wątków (i całej reszty…) zależy to czy A zobaczy "foo" w mapie czy nie.

Natomiast wyjątek poleci jeśli A będzie robić coś takiego:

     for(String a : list){
        /* cośtam */
    }

Natomiast w tym czasie (jakikolwiek wątek) zrobi:

    list.remove(1);

Wyjątek poleci nawet jeśli w w jednym wątku zostanie wykonane:

    for(Map.Entry<String, String> me : map.entrySet()){
        if(/*warunek*/){
            map.remove(me.getKey());
        }
    }

Tutaj synchronizacja nic nie pomoże.

Co gwarantuje synchronizacja
Że z kodu pobierającego własności z mapy nie będą leciały inne dziwne wyjątki.

Rozwiązanie tego problemu

Użyć odpowiendiem kolekcji z java.util.concurrent. Na przykład: ConcurrentSkipListMap działa w ten sposób że iteratory i widoki pokazują stan kolekcji z jakiegoś konkretnego punktu w czasie (i zmiany które nastąpiły po tym punkcie nie są odzwierciedlane).

StringBuffer

Nie używaj

Koszty synchronizacji

Synchronizacja jest bardzo drogą operacją. Wątki mają obowiązek synchronizować swój kesz z pamięcią główną podczas zdobywania klucza lub oddawania go (czyli podczas wchodzenia i wychodzenia z bloku synchronizowanego). A takie kopiowanie pamięci może być drogie i długotrwałe.

Deadlocki

Patrz thinking in java…

volatile

Jeśli zmienna jest volatile znaczy to tyle że wątek nie ma prawa skopiować jej do swojego kesza. Oraz że wszystkie dostępy (odczyty i zapisy) do zmiennych volatile będą się odbywać w tej kolejności co było w kodzie napisane.

Do czego służy volatile:

Jeśli jakaś zmienna ma być dostępna dla wielu wątków trzeba ją oznaczyć jako volatile.

Na przykład:

    class MyThread extends Thread{    
        private boolean kill = false;
        void kill(){
            kill = true; 
        }
        void doStuff(){
            /*Doing stuff*/
        }
        void run(){
            while(!kill){
                doStuff();
            }
        }
    }
    public static void main(String[] args){
        MyThread t = new MyThread();
        t.start();
        t.kill();
 
    }

MyThread ma działać tak że jeśli ktoś wywoła na obiekcie kill() zostanie ustawiona zmienna kill i wątek się po jakimś czasie wyłączy. Jest to bardzo często używany wzorzec - bo powoduje w miarę czyste zabicie wątka w sposób kontrolowany.

Ale to w ten sposób nie zadziała. Sekwencja zdarzeń będzie raczej taka:

  1. Utworzymy wątek
  2. Wywołamy funkcję start. W tym momencie zmienna kill jest kopiowana do pamięci wątku.
  3. Ustawiamy kill na true w pamięci głównej (ale wątek tego nie widzi), bo ma się synchronizować tylko w odpowiednich momentach

Żeby to zadziałało trzeba ustawić kill jako volatile.

private volatile boolean kill = false;

[1]

volatile a long i double

No to zgrubsza chodzi o to że JVM ma prawo zapisywać longa w dwóch rzutach - w piewszym pierwsze 32 bity - w drugim drugie. To może powodować odczyty bezsensownych danych. Jeśli zmienne są volatile nie będzie to możliwe.

Ale:
Żadna nowoczesna JVM tego nie robi

Do czego nie służy TODO

TODO

Niezmienność

Jeśli jakiś obiekt nie zmienia swojego stanu to jest bezpieczny.

Co to znaczy niezmienny.

Niezmienny nie znaczy nie zmienił swojego stanu od momentu utworzenia. Znaczy [2]:

  1. Można do niego dojść po ścieżce referencji z których pierwsza jest final.
  2. Zmienna final nie opuściła konstruktora przed jego wykonaniem.
  3. Obiekt sie nie zmienił się od czasu wykonania.

Dokładniej:

  1. W tym przykładzie foo.bar.baz spełnia pierwszy warunek
    class Bar{
        int baz;
    }
    class Foo{
        final Bar bar; 
    }
  1. 'Zmienna final nie opuściła konstruktora przed jego wykonaniem'

Z grubsza chodzi o to że wyrażenia mogą zostać poprzestawiane i jeśli mamy coś takiego:

    class Bar{
        public static Bar lastConstructedBar; 
        int baz;
    }
    class Foo{
        final Bar bar; 
        Foo(){
            bar =  new Bar(); 
            bar.baz = 1; 
            Bar.lastConstructedBar = bar;  
        }
    }

To w konstruktorze polecenia mogą zostać poprzestawiane do:

    Foo(){
            bar =  new Bar(); 
            Bar.lastConstructedBar = bar;  
            bar.baz = 1;         
        }

I jakiś wątek zobaczy bar ze zmienną baz ustawioną na 0. Zapisze sobie w keszu i już nigdy nie odczyta…

Atomowość

Operacja atomowe są bezpieczne dla wielu wątków.

Operacja atomowa to operacja w której nie ma stanu pośredniego, więc żaden wątek nie może odczytać złych danych (czyli właśnie tego stanu pośredniego) bo ich nie ma!

Nie to złoto co się świeci

Następujące operacje nie muszą być atomowe:

    i ++;
    i = 2L;

i tak dalej…

java.util.concurrent.atomic

CAS

Główną operacją atomową jest CAS - Compare And Set. Rozważmy takie coś - mamy sobie generator liczb losowych, który ma sobie zmienną seed żeby generator działał w wielu wątkach, ale nie chcemy go explicite synchronizować. Nie może też być tak że zwróci (nawet w dwóch wątkach) tą samą liczbę losową.

Czyli musimy zrobić takie operacje (pseudokod)

    long seed = this.seed; 
    /*inicjalizacja nowej wartości ziarna*/ //1
    this.seed = seed; //Zapisanie nowej wartości ziarna.
    /*wygenerowanie z ziarna liczby losowej (czyli inta)*/ 
    return random;

Jedyną operacją która nas martwi jest 1. Może być tak że:

Wątek A odczyta this.seed.
Wątek B odczyta this.seed.
Wątek A zapisze nową wartość seed

No i oba zwrócą tą samą liczbę losową.

Robimy więc coś takiego:

  1. Odczytujemy do zmiennej oldSeed wartość ziarna.
  2. Generujemy do zmiennej newSeed nową wartość ziarna.
  3. Ustawiamy ziarno w obiekcie tylko jeśli się nie zmieniło. To znaczy że jeśli this.seed == oldSeed ustawiamy wartość. Jeśli nie wracamy do punktu 1.

java.util.Random

Na marginiesie: java.util.Random właśnie tak działa.

        long oldseed, nextseed; 
        AtomicLong seed = this.seed; 
        do {
        oldseed = seed.get(); //Pobranie aktualnej wartości zmiennej
        nextseed = (oldseed * multiplier + addend) & mask; //Wygenerowanie nowej
        } while (!seed.compareAndSet(oldseed, nextseed)); //Jeśli aktualna wartość 
        //się nie zmieniła to zapisujemy ją - jeśli nie to jeszcze raz. 
        return (int)(nextseed >>> (48 - bits));

Atomowe operacje arytmetyczne

Operacje arytmetyczne nie są atomowe:

    stanKonta+=20;

Składa się z:

  1. Odczytu wartości
  2. Dodania wartości
  3. Zapisu wartości

Może więc być tak:

  1. Wątek A czyta wartość stanKonta
  2. Wątek B czyta wartość stanKonta
  3. Wątek A dodaje 20 i zapisuje
  4. Wątek B dodaje 20 i zapisuje

I stan kąta wzrośnie o 20 (a nie 40!)

Stąd mamy w java.util.concurrent.atomic operacje takie jak incrementAndGet czy addAndGet które atomowo wykonują te operacje.

Duże implementacje korzytające tylko z atomowości:

Lock-Free HashTable

Inne podejścia

Można też do problemów wielowątkowości podejść od innej strony. To znaczy da się napisać program w którym wszyscy mają dostęp do wszystkiego a mimo to daje radę (z użyciem minimalnej synchronizacji).

Wzorzec Master - Worker

Mamy jeden wątek który jest wątkiem Master i odpowiada za COŚ, na przykład za interakcję z użytkownikiem, który wszystkie działania wymagające czasu (lub mogące się zablokować) deleguje do innych wątków robotników (które to zadanie wykonują asynchronicznie) i po jakimś czasie zwracają odpowiedź.

Swing używa właśnie tej architektury - wszystkie operacje na komponentach swingowych2 powinny być wołane ze specjalnego wątku zwanego EDT (Event Dispatching Thread).

Jeśli EDT się zablokuje (albo nagle zacznie coś obliczać) to cały interfejs przestanie odpowiadać. Dlatego wszystkie długotrwałe operacje powinno się wykonywać z innych wątków a w EDT zwracać ich wyniki.

Żeby to ułatwić JDK6 dostarcza klasę SwingWorker. Która jest zasadniczo itemem roboty do wykonania poza EDT i która potrafi po wykonaniu roboty odświerzyć UI.

Najporstsze użycie jest mniej więcej takie:

    SwingWorker foo = new SwingWorker(){
 
        //Wykonywane poza EDT.
        Object doInBackground(){
            /*Jakaś strasznie ciężka operacja, na 
            przykład czytanie pliku */
            return result; 
        }
 
        //Wykonywane w EDT
        void done(){
            Object result = get();
            /* Wyświetlenie wyniku */
        }
 
    }

data: 13 Dec 2009 22:39 tagi: concurrency


Wielkie Notatki

Notatki z tych wykładów z Wielkich eksperymentów w historii Fizyki na których byłem i byłem przytomny

na moim serwerze.

data: 13 Dec 2009 14:41 tagi:


Fizyka Wielkie Eksperymenty W Historii Fizyki Notatki

Notatki z tych kilku wykładów na których byłem i byłem przytomny.

Są na moim serwerze

data: 13 Dec 2009 14:03 tagi:

strona 1 z 212następna »

O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-NonCommercial-NoDerivs 3.0 License