Sobes.tech
Middle

Ինչու են առաջանում թելերի մրցումները և ինչ միջոցներ կան դրանց դեմ պայքարելու համար։

sobes.tech AI

Պատասխան AI-ից

Ռեյսային պայմաններ (race conditions) առաջանում են, երբ միաժամանակ մի քանի թելեր մուտք են գործում ընդհանուր փոփոխվող տվյալներ և նրանց կատարումը կախված է դրանց կատարելու կարգից։ Դա տեղի է ունենում, քանի որ օպերացիոն համակարգը կարող է ցանկացած պահի փոխարկել թելերը, ընդհատելով նրանց կատարումը։

Պայքարի միջոցներ՝

  • Սինխրոնիզացիա: Սինխրոնիզացիայի պրիմիտիվների օգտագործում՝ ապահովելու բացառիկ մուտք դեպի ընդհանուր ռեսուրսներ։

    • synchronized բանալի բառը: Կիրառվում է մեթոդների կամ կոդի բլոկների վրա։ արգելափակում է մուտքը օբյեկտի կամ դասի համար այլ թելերի համար, մինչեւ որ ընթացիկ թելը ավարտի սինխրոնիզացված բլոկի/մեթոդի կատարումը։

      // Սինխրոնիզացված մեթոդ
      public synchronized void updateData(int newValue) {
          // ... ընդհանուր տվյալների թարմացում
      }
      
      // Սինխրոնիզացված կոդի բլոկ
      public void processData() {
          synchronized (this) { // կամ այլ մոնիտոր օբյեկտ
              // ... հասանելիություն ընդհանուր տվյալներին
          }
      }
      
    • Ապակողպելներ (Lock): Ավելի ճկուն վերահսկողություն են ապահովում սինխրոնիզացիայի նկատմամբ՝ համեմատած synchronized-ի հետ։

      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
      
      private final Lock dataLock = new ReentrantLock();
      
      public void safeUpdateData(int newValue) {
          dataLock.lock(); // Ապակողպել վերցնել
          try {
              // ... ընդհանուր տվյալների թարմացում
          } finally {
              dataLock.unlock(); // Ապակողպել ազատել
          }
      }
      
  • Ատոմային փոփոխականներ (Atomic...): Առանց բացահայտ ապակողպելու՝ ապահովում են հոսքերի անվտանգ գործողություններ՝ հիմնական տիպերի վրա։ Օգտագործվում են պարզ գործողությունների համար (ինկրեմենտ, համեմատում և փոխանակում):

    import java.util.concurrent.atomic.AtomicInteger;
    
    private final AtomicInteger counter = new AtomicInteger(0);
    
    public void incrementCounter() {
        counter.incrementAndGet(); // Ատոմային ավելացում
    }
    
  • Հոսքերի անվտանգ հավաքածուներ: Օգտագործում են հատուկ հավաքածուներ՝ java.util.concurrent փաթեթից (օրինակ՝ ConcurrentHashMap, CopyOnWriteArrayList), որոնք նախագծված են բազմահոսքային մուտքի համար։

    import java.util.concurrent.ConcurrentHashMap;
    import java.util.Map;
    
    private final Map<String, Integer> safeMap = new ConcurrentHashMap<>();
    
  • Անփոփոխ (Immutable) օբյեկտներ: Եթե տվյալները չեն փոխվում ստեղծելուց հետո, ապա կարելի է անվտանգ օգտվել դրանցից միաժամանակ մի քանի հոսքից՝ առանց սինխրոնիզացիայի։

  • ThreadLocal հոսքի տեղական փոփոխականներ: Յուրաքանչյուր հոսք ստանում է իր սեփական պատճենը, ինչը բացառում է մրցակցությունը հասանելիության համար։

    private final ThreadLocal<Integer> threadId = new ThreadLocal<>();
    
    public void setThreadId() {
        threadId.set(Thread.currentThread().getId());
    }
    
    public int getThreadId() {
        return threadId.get();
    }
    
  • Արդյունավետ նախագծում՝ ճարտարապետություն: Հիմնական փոփոխվող տվյալների նվազեցում և ասինխրոն մոտեցումների կամ հաղորդագրությունների փոխանցման օգտագործում՝ մրցակցությունը նվազեցնելու համար։