„Здравей, Амиго! Помниш ли, че Ели ти каза за проблемите, които възникват, когато няколко нишки се опитват едновременно да получат достъп до споделен ресурс, нали?“
— Да.
"Работата е там, че това не е всичко. Има още един малък проблем."
Както знаете, компютърът има памет, където се съхраняват данни и команди (code), Howто и процесор, който изпълнява тези команди и работи с данните. Процесорът чете данни от паметта, променя ги и ги записва обратно в паметта. За да ускори изчисленията, процесорът има собствена вградена "бърза" памет: кеш паметта.
Процесорът работи по-бързо, като копира най-често използваните променливи и области от паметта в своя кеш. След това прави всички промени в тази бърза памет. И след това копира данните обратно в «бавната» памет. През цялото това време бавната памет съдържа старите (непроменени!) променливи.
Тук възниква проблемът. Една нишка променя променлива , като isCancel or isInterrupted в примера по-горе, но втора нишка «не вижда тази промяна , защото се е случила в бързата памет. Това е следствие от факта, че нишките нямат достъп до кеша на другия. (Един процесор често съдържа няколко независими ядра и нишките могат да работят на физически различни ядра.)
Да си припомним вчерашния пример:
Код | Описание |
---|---|
|
Нишката «не знае», че другите нишки съществуват.
В метода run променливата isCancel се поставя в кеша на дъщерната нишка, когато се използва за първи път. Тази операция е еквивалентна на следния code:
Извикването на метода за отмяна от друга нишка ще промени стойността на isCancel в нормалната (бавна) памет, но не и в кешовете на други нишки. |
|
„Уау! И измислиха ли красиво решение и за това, като например със синхронизирано ?“
— Няма да повярвате!
Първата мисъл беше да деактивирам кеша, но това направи програмите да работят няколко пъти по-бавно. Тогава се появи друго решение.
Роди се променливата ключова дума . Поставяме тази ключова дума преди декларация на променлива, за да покажем, че нейната стойност не трябва да се поставя в кеша. По-точно, не че не можеше да се постави в кеша, а просто винаги трябваше да се чете и записва в нормалната (бавна) памет.
Ето How да коригираме нашето решение, така че всичко да работи добре:
Код | Описание |
---|---|
|
Модификаторът volatile кара дадена променлива винаги да се чете от и записва в нормална памет, споделена от всички нишки. |
|
"Това е?"
„Това е. Просто и красиво.“
GO TO FULL VERSION