Techniki Zaawansowane
8 godz. 35 min · Java · Full-stack i Programowanie
Rafał SolarskiW poczatkowych lekcjach przyjrzymy sie pokladowi, na jakim bedziemy uruchamiali nasze programy. Wykorzystamy VisualVM do podgladania parametrów JVM. Zobaczymy równiez jakie zasoby sa tam dostepne oraz dowiesz sie jak monitorowac to, czy dobrze z nich korzystamy. Opowiemy Ci tez miedzy innymi o tym, jak zrobic heap i thread dump, oraz jak wlaczyc logi GC.
Kolejne lekcje kursu zostaly poswiecone wyrazeniom regularnym. Wyrazenia regularne mozemy wykorzystac nie tylko do walidacji danych wprowadzania przez uzytkownika, ale równiez do dzielenia tekstu oraz wyluskiwania wystapien wzorców w duzym tekscie. W tym rozdziale dowiemy sie miedzy innymi tego, jak mozemy wykorzystac ten potencjal z poziomu Javy.
Dzieki typom generycznym jestesmy w stanie osiagnac bezpieczenstwo typów w trakcie kompilacji przy zachowaniu elastycznosci pisanego kodu. W nastepnym rozdziale kursu przyjrzymy sie temu, jak mozemy je wykorzystac, oraz w jaki sposób czasami nalezy z tego bezpieczenstwa zrezygnowac.
Interfejsy funkcyjne to sposób na przeniesienie odrobiny swiata programowania funkcyjnego do Javy. Gdy polaczymy je z wyrazeniami lambda oraz API strumieni pozwola nam pisac te sama logike w duzo bardziej przejrzysty sposób.
Kolekcje, czyli listy, mapy, zbiory i kolejki to jedne z najczesciej wykorzystywanych klas w codziennej pracy. To jak dobrze poznamy ich mozliwosci ma ogromny wplyw na to, w jaki sposób bedziemy podchodzili do rozwiazywania wyzwan na naszej drodze.
System plików to zasób bez którego ciezko sobie poradzic. Pozwalaja nam na dostarczanie konfiguracji, danych wejsciowych i wyjsciowych, a przez to równiez integrowanie ze soba calych systemów.W tym rozdziale nauczymy sie korzystac z tych dobrodziejstw w bezpieczny sposób wykorzystujac m.in. IO Streams.
Trzymanie daty w String to niekoniecznie najwygodniejszy sposób. Juz od pewnego czasu Java dysponuje bardzo wygodnym Date&Time API - zobaczymy, co mozemy w nim znalezc.
Wielowatkowosc nie jest prosta... i dlugo tak jeszcze pozostanie. Nawet jesli korzystamy z frameworków, które próbuja ja przed nami ukryc, to ciagle musimy byc swiadomi problemów jakie sie z nia wiaza. W tym rozdziale poznamy glówne problemy na jakie mozna natrafic programujac wielowatkowo w Javie. Poznamy równiez klasy, które zdecydowanie pomoga nam zapanowac nad ta zlozonoscia.
JDBC to najbardziej podstawowy sposób laczenia sie z baza SQL z poziomu Javy. W wielu systemach/aplikacjach stosuje sie rozwiazania ORM takie jak JPA/Hibernate. Mimo wszystko warto wiedziec jak to pod spodem dziala oraz umiec poradzic sobie w aplikacjach, gdzie wybrano bardziej "lekkie" podejscie niz Hibernate.
Na koniec kursu wykorzystamy zdobyta wiedze, aby stworzyc prosta aplikacje pozwalajaca na przechowywanie danych o wydatkach. Po stworzeniu coreu aplikacji, mozesz spróbowac uzupelnic go za pomoca GUI.
Ten kurs stworzony zostal przede wszystkim z mysla o osobach, które juz poznaly podstawy jezyka, takie jak zmienne, mechanizmy kontroli wykonania, klasy, typy generyczne.Jezeli chcesz poczuc sie swobodnie nie tylko jesli chodzi o mechanizmy jezyka, ale równiez pod wzgledem znajomosci standardowej biblioteki Javy - to kurs w sam raz dla Ciebie. Materialy beda przydatne dla studentów, którzy znaja juz podstawowa skladnie Javy; programistów Javy chcacych poszerzyc lub uporzadkowac swoja wiedze; programistów innych jezyków, którzy chca poznac inny stack technologiczny.
Cześć witam cię bardzo serdecznie w
tej lekcji już zaczniemy zajmować tym jak implementować
bezpiecznie kod który jest wielowątkowy tak do tej pory nauczyliśmy
się jak używać future'ów executorów i tak dalej a teraz zobaczymy jak
to zrobić żeby faktycznie mieć to thread safety sposób w jaki
będziemy się uczyli to będzie taki że ja będę prezentował pewien problem kawałek
kodu który powinien działać ale z jakiegoś powodu nie działa oraz
zobaczymy jak jesteśmy w stanie go poprawić w tej lekcji zajmiemy
się czymś co się nazywa visibility problem zacznijmy
od kodu mamy jakiś fragment kodu jest tutaj pewien taki pattern
służący do zatrzymywania wątku który jest powiedzmy sterowany
z zewnątrz jakąś zmienną tak tu mamy jakąś flagę i ten wątek
zaczyna swoją pracę ma tutaj jakiegoś takiego infinite loop'a który się zakończy
w momencie kiedy z zewnątrz ustawimy stop tak stop jest tutaj niestety
zmienną mutowalną z zewnątrz tak czyli jest współdzieloną zmienną mutowalną
okej czyli startujemy wątek on tutaj mieli w nieskończoność
do momentu kiedy my tutaj odczekamy sekundę i ustawimy mu true tak i
później kończy się main i powiedzmy ten wątek też już powinien być zakończony mniej więcej powinno
działać intuicyjnie wydaje się że powinno zajrzymy teraz co tu się wydarzy i
jak widzimy nasz menu się zakończył no ale program się nie zakończył
tak nie mamy wyświetlonej tej frazy tak tego zdania no okej
i co to się teraz zadziałało problem polega na tym że w momencie
tworzenia tego thread'u tutaj dostajemy coś co możemy sobie wyobrażać
jako snapshot zmiennej tak dostajemy stopa ustawionego na false
i w momencie kiedy my tutaj ustawiamy na true to
ten wyjątek nawet tego nie widzi on tu jest jakoś tak zafiksowany że patrzy
cały czas na ten tak może też być tak że ustawienie tego powiedzmy
ustawia tą zmienną tak jakby tylko dla tego wątku tak to jest tak zwane
przekraczanie memory barrier możemy sobie wyobrazić że każdy
thread który tworzymy ma pewnego rodzaju snapshot wszystkich
zmiennych tak no i teraz jeżeli my zmieniamy coś w jednym threadzie to
nawet nie może nie być zapisane do jakiejś powiedzmy main memory tylko
gdzieś tutaj lokalnie sobie jest zapisane tak i teraz odczyt w drugim
wątku może tego w ogóle nie zauważyć może w ogóle nie przechodzi do main memory tylko
szuka sobie jakąś taką powiedzmy thread local version tak coś takiego
okej i teraz główny problem z tym
z tym visibility problem jest taki że to czasami działa
a czasami nie tutaj jak coś zauważysz ja ten w ogóle ten fragment
kodu ja musiałem trochę poeksperymentować żeby doprowadzić do tego żeby mieć
ten efekt ze on teraz nie wyłącza tego wątku tak na
innej platformie powiedzmy na jakimś innym jvm na jakimś innym komputerze
mogłoby być tak że optymalizator javy w ogóle by tego powiedzmy
na nim by to zadziałało w sensie on by zauważył że okej stop
się zmienił tak zauważ sobie że na przykład jak ja tutaj dodam jakąś linijkę
to przypadkowo zupełnie w tym momencie teraz zachowa się tak
jakbyśmy tego chcieli tak to jest przypadkowe i oczywiście
trochę specyficzne to wynika z pewno jakiś taki implementacji pod spodem która
może się zmienić która może brać pod uwagę wiele jakichś takich zmiennych związanych z
platformą prawda w każdym razie łatwiej jest wymusić żeby on powiedzmy omijał
to memory barrier niż wymusić żeby nie ominą tak okej
teraz pokażę ci trzy sposoby w jakie jesteśmy sobie w stanie z tym poradzić
tak ich jest więcej ale te nam powinny zupełnie wystarczyć pierwszy
sposób w jaki jesteśmy w stanie sobie poradzić tutaj to jest dodanie modyfikatora
volatile dalej do tej zmiennej dzięki temu każdy zapis i odczyt tej
zmiennej będzie przekraczał właśnie tą barierę pamięci tak czyli
będzie zapisywał we właściwe miejsce i odczytywał zawsze
tą oryginalną wartość teraz zobaczymy sobie jak teraz zadziała nasz kod i jak
widzimy kod zakończył się prawidłowo tak mamy tutaj zakończyliśmy
maina i też ten też został zakończony prawda zauważ że volatile
on też nie załatwia sprawy zapisu synchronizacji
do tego do tej zmiennej tak on tylko tutaj w tym momencie zapewnia
że zapiszemy właściwą wartość tak we właściwe miejsce i to będzie widoczne
dla innych wątków taka jest powiedzmy gwarancja tego czegoś kolejnym
sposobem jest wykorzystanie pewnego wrappera jest to atomic boolean
powiedzmy to jest obiekt z tego względu możemy tutaj też zastosować final to
jest też całkiem fajne tworząc atomic boolean my tutaj mu wskazujemy jakąś
inicjalna wartość tego obiektu później możemy po prostu zrobić na
tym stop ta sztuczka polega na tym że atomic boolean w środku
trzyma boola po prostu tak to jest pewien wrapper a właściwie
nawet inta tak ale on przede wszystkim i jest volatile tak czyli
też zapewnia przekraczanie tej memory barrier tak
okej to też nam zadziała tym momencie poza tym że mamy
powiedzmy wrappera tak że mamy to volatile i to też atomic boolean oraz
inne wrappery to na przykład atomic integer atomic long i
tak dalej też dodają kilka metod które zapewniają nam atomowe
operacje na tych zmiennych tak które są pod spodem one są mutowalne
wewnętrznie ale jesteśmy powiedzmy w stanie odpowiednio tam jakoś
zmanipulować i mieć powiedzmy takie atomowe operacje tak na przykład
możemy na atomic longu możemy atomowo implementować go tak
co jest thread safety tak wtedy oczywiście jeszcze pytanie
do czego to użyjemy okej lecimy dalej ostatnim z prezentowanych
sposobów jest wykorzystanie takiego modyfikatora synchronized
synchronized możemy tworzyć i powiedzmy tworzyć to na jakimś bloku
kodu ale możemy też na metodzie i teraz synchronized robi coś takiego jeżeli mamy
jakąś metodę tutaj to do środka może wejść tylko jeden wątek tak
tutaj i tutaj może wejść jeden wątek naraz jak on
skończy powiedzmy swoje wykonanie no to może wejść drugi ale drugim takim powiedzmy
efektem jest to że jeżeli robimy synchronized przy
zapisie i odczycie danej zmiennej która powiedzmy jest mutowalna
to teraz mamy gwarancję że zostanie przekroczone właśnie memory barrier
jak sobie zobaczymy to też nam zadziała okej synchronized jest też wykorzystywany
do synchronizowania zapisu i odczytu na przykład jeżeli mamy jakąś operację która
wymaga najpierw odczytania zmiennej wykonania jakiejś logiki jak podjęcia jakiejś
decyzji później jeszcze raz zapisania do tej zmiennej tutaj jeżeli chcemy uniknąć tak
zwanego race conditions możemy też wykorzystać właśnie synchronized ale o tym dowiemy się
też w kolejnych lekcjach okej czyli podsumowując możemy wykorzystać
sobie volatile co jest takim powiedzmy takim najbardziej niskopoziomowy modyfikatorem
takim rozwiązanie w tej kwestii możemy wykorzystać sobie synchronized możemy
też wykorzystać wrapper jakim jest atomic boolean tak oczywiście
tutaj w tym patternie też zauważ że jak mieliśmy tutaj w ogóle ten pattern
że chcemy zastopować jakąś wykonanie jakiegoś threada jakichś operacji
z poziomu jakiegoś innego thread'a który utworzył też ten wątek i ma
dostęp do tego wątku w ogóle tak to możemy też tutaj zastosować
ten patent interrupt tak i w tym momencie sprawdzać current thread
is interrupted tak i odpowiednio w zależności od tego reagować
tak i zakończ na przykład pracę okej jeżeli chodzi o visibility problem
no to jest wszystko dzięki wielkie za uwagę i do zobaczenia w kolejnej lekcji