Vad innebär egentligen trådsäkerhet respektiva motsatsen? En anledning för att tex inte använda statiska metoder är för trådsäkerhet men på vilket sätt är inte trådar säkra när man använder sig av statiska metoder? Har ni någonsin haft problem med att trådarna inte är säkra?
class X {
private X(){}
private static X instance;
public static X getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
Då tror man ju gärna att det bara kan uppstå en enda instans av klassen X, men om två trådar anropar getInstance samtidigt kan följande scenario uppstå:
Tråd A kommer in i getInstance och ser att instance är null.
Tråd A börjar skapa en ny X.
Tråd B kommer in i getInstance och ser att instance är null.
Tråd B börjar skapa en ny X.
Tråd A är klar med att skapa en X, och sätter instance att peka på den.
Tråd B är klar med att skapa en X, och sätter instance att peka på den.
Tråd A returnerar instance, d.v.s. det objekt som skapats av tråd B.
Tråd B returnerar instance, d.v.s. det objekt den skapade själv.
Nu har vi skapat två instanser av X, vilket kan vara problematiskt i vissa fall och oavsett vilket är det inte det vi avsett ska hända. Så för att göra getInstance trådsäker skulle vi skriva så här:
class X {
private X(){}
private static X instance;
private Object instanceLock = new Object();
public static X getInstance() {
lock (instanceLock) {
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
Då skulle koden köras ungefär så här:
Tråd A kommer in i getInstance och begär ett lås på instanceLock, vilket den får eftersom det inte finns något lås på det objektet än.
Tråd A ser att instance är null.
Tråd A börjar skapa en ny X.
Tråd B kommer in i getInstance och begär ett lås på instanceLock, men eftersom tråd A har det låset väntar tråd B på att låset ska släppa.
Tråd A är klar med att skapa en X, och sätter instance att peka på den.
Tråd A returnerar instance och släpper sitt lås på instanceLock.
Tråd B får låset på instanceLock, ser att instance inte är null, och returnerar instance.
Statiska metoder är inte mer eller mindre trådsäkra än andra metoder, det är när samma metod anropas på samma objekt (som håller reda på samma resurser) som det kan uppstå problem, som i singletonexemplet.
Tack för en väldigt bra förklaring och det är så jag tänkt mig det hela. Men hur kommer det sig att vissa påstår att statiska metoder inte är trådsäkra? Det har jag aldrig riktigt förstått. Någon som kan förklara?
Men hur kommer det sig att vissa påstår att statiska metoder inte är trådsäkra? Det har jag aldrig riktigt förstått. Någon som kan förklara?
För att utöka erka's svar så kan man säga följande:
Om du anropar en statisk metod, så allt som sker inom denna metod, alltså alla variabler som skapas inom denna metod hamlar i en egen minnesrymd, så om 2 trådar anropar denna metod samtidigt så bildas 2 minnesrymder oberoende av varandra som håller variable informationen åtskilda, alltså är denna statiska metod trådsäker.
Men om du tar spango's exempel ovan så använder sig hans metod av en "gemensam" variabel, alltså om 2 trådar anropar hans metod, så kommer båda trådarna operera på samma minnerymd, det betyder att en tråd kanske skriver till minnet medans den andra läser ifrån samma minnesrymd, det blir helt enkelt fel, och metoden är inte trådsäker.
Nu har detta inget med statiska metoder att göra, utan alla variabler som du kan accessa samtidigt från mer än 1 tråd kan ge dig problem med trådhantering. Man brukar lösa sådan problem med mutex() eller Lock() operatorer, men då kan man få andra problem som dead-locks och raise conditions... så man skall hålla tungan rätt i mun när man börjar operera med flera trådar, speciellt som dessa fel nästan uteslutande visar sig i produktion och nästan aldrig i de små tester som man själv gör :(
Men hur kommer det sig att vissa påstår att statiska metoder inte är trådsäkra? Det har jag aldrig riktigt förstått. Någon som kan förklara?
För att utöka erka's svar så kan man säga följande:
Om du anropar en statisk metod, så allt som sker inom denna metod, alltså alla variabler som skapas inom denna metod hamlar i en egen minnesrymd, så om 2 trådar anropar denna metod samtidigt så bildas 2 minnesrymder oberoende av varandra som håller variable informationen åtskilda, alltså är denna statiska metod trådsäker.
Men om du tar spango's exempel ovan så använder sig hans metod av en "gemensam" variabel, alltså om 2 trådar anropar hans metod, så kommer båda trådarna operera på samma minnerymd, det betyder att en tråd kanske skriver till minnet medans den andra läser ifrån samma minnesrymd, det blir helt enkelt fel, och metoden är inte trådsäker.
Nu har detta inget med statiska metoder att göra, utan alla variabler som du kan accessa samtidigt från mer än 1 tråd kan ge dig problem med trådhantering. Man brukar lösa sådan problem med mutex() eller Lock() operatorer, men då kan man få andra problem som dead-locks och raise conditions... så man skall hålla tungan rätt i mun när man börjar operera med flera trådar, speciellt som dessa fel nästan uteslutande visar sig i produktion och nästan aldrig i de små tester som man själv gör :(
- M
Det är just därför man i designfasen måste tänka efter riktigt noga och göra diagram som kan avslöja dessa deadlock, starvation osv...
Men som Gladh skriver missar många ofta detta och hastar sig igenom designfasen om dom ens har någon.
261 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2