এই শ্রেণিটি কেন থ্রেড নিরাপদ নয়?


95
class ThreadSafeClass extends Thread
{
     private static int count = 0;

     public synchronized static void increment()
     {
         count++;
     }

     public synchronized void decrement()
     {
         count--;
     }
}

উপরের শ্রেণিটি থ্রেড নিরাপদ নয় কেন কেউ ব্যাখ্যা করতে পারেন?


6
আমি জাভা সম্পর্কে জানি না, তবে দেখে মনে হচ্ছে those সমস্ত পদ্ধতি পৃথক পৃথকভাবে থ্রেড-নিরাপদ, তবে একই পদ্ধতিতে আপনার প্রতিটি পদ্ধতিতে একটি থ্রেড থাকতে পারে । আপনার যদি একটি একক পদ্ধতি থাকে যা একটি বুল নেয় ( increment) এটি থ্রেড নিরাপদ। বা যদি আপনি কিছু লকিং অবজেক্ট ব্যবহার করেন। যেমনটি আমি বলেছি, আমি জাভা সম্পর্কে জানি না - আমার মন্তব্য সি # জ্ঞান থেকে এসেছে।
ওয়াই হা লি


আমি জাভেরিটিও ভালভাবে জানি না, তবে একটি স্ট্যাটিক ভেরিয়েবলের অ্যাক্সেস সিঙ্ক্রোনাইজ করতে, synchronizedকেবল স্থির পদ্ধতিতে ব্যবহার করা উচিত। সুতরাং আমার মতামতটিতে আপনি যদি incrementপদ্ধতিটি সরিয়ে ফেলেন , এটি এখনও থ্রেডসেফ নয় কারণ দুটি উদাহরণ (যা কেবল একই উদাহরণের মাধ্যমে কেবলমাত্র সিঙ্ক্রোনাইজ অ্যাক্সেস পেয়েছে) পদ্ধতিটিকে একই সাথে কল করতে পারে।
অনুর

4
আপনি যতক্ষণ ক্লাসের কোনও উদাহরণ তৈরি না করেন ততক্ষণ এটি থ্রেড নিরাপদ।
বেনিয়ামিন গ্রুইনবাউম

4
আপনি কেন ভাবেন যে এটি থ্রেড নিরাপদ নয়।
রায়েডওয়াল্ড

উত্তর:


134

যেহেতু incrementপদ্ধতিটি staticএটি শ্রেণীর অবজেক্টের জন্য সিঙ্ক্রোনাইজ হবে ThreadSafeClassdecrementপদ্ধতি স্ট্যাটিক নয় এবং সুসংগত করা হবে উদাহরণস্বরূপ সেটিতে কল করার জন্য ব্যবহার করা হয়। অর্থাৎ, তারা বিভিন্ন অবজেক্টে সিঙ্ক্রোনাইজ করবে এবং এভাবে দুটি পৃথক থ্রেড একই সাথে পদ্ধতিগুলি কার্যকর করতে পারে। যেহেতু ++এবং --অপারেশনগুলি পারমাণবিক নয় তাই ক্লাসটি থ্রেড নিরাপদ নয়।

এছাড়াও, যেহেতু countহয় static, থেকে এটা পরিবর্তন decrementযা সিঙ্ক্রোনাইজ করা আছে উদাহরণস্বরূপ পদ্ধতি অনিরাপদ যেহেতু এটি বিভিন্ন দৃষ্টান্ত উপর বলা যেতে পারে এবং সংশোধন countউপায় যে একই সময়ে।


12
আপনি সাল থেকে যোগ করতে পারেন countহয় staticএকটি দৃষ্টান্ত পদ্ধতি হচ্ছে decrement()এমনকি যদি সেখানে ছিল না, ভুল static increment()দুটি থ্রেড ডাকা যাবে পদ্ধতি, decrement()একই সময়ে একই কাউন্টার পরিবর্তন বিভিন্ন দৃষ্টান্ত হবে।
হলগার

4
যে সম্ভবত ব্যবহার পছন্দ করা একটি ভাল কারণ synchronizedপরিবর্তে পদ্ধতির উপর পরিবর্তক ব্যবহার করে, অর্থাত সাধারণ ব্লক (এমনকি পুরো পদ্ধতি বিষয়বস্তু দিকে) synchronized(this) { ... }এবং synchronized(ThreadSafeClass.class) { ... }
ব্রুনো

++এবং --এটি পারমাণবিকও নয়volatile intSynchronizedসঙ্গে পড়া / আপডেট / লেখা সমস্যা যত্ন নেয় ++/ --কিন্তু staticশব্দ হয়, ভাল, কী এখানে। ভাল উত্তর!
ক্রিস সাইরেফাইস

পুনরায়, [একটি স্থিতিশীল ক্ষেত্র] থেকে ... সংশোধন করা একটি সিঙ্ক্রোনাইজড ইনস্ট্যান্স পদ্ধতিটি ভুল : একটি উদাহরণ পদ্ধতির মধ্যে থেকে একটি স্ট্যাটিক ভেরিয়েবল অ্যাক্সেস করার সহজাতভাবে ভুল নেই এবং synchronizedউদাহরণস্বরূপ পদ্ধতি থেকে এটি অ্যাক্সেস করার সাথে অন্তর্নিহিত কোনও ভুল নেই । স্থির তথ্যের জন্য সুরক্ষা সরবরাহ করার জন্য উদাহরণ পদ্ধতিতে কেবল "সিঙ্ক্রোনাইজড" আশা করবেন না। এখানে আপনার প্রথম অনুচ্ছেদে একমাত্র সমস্যাটি ছিল: একই তথ্য রক্ষা করার জন্য পদ্ধতিগুলি বিভিন্ন লক ব্যবহার করে এবং অবশ্যই এটি কোনও সুরক্ষা দেয় না।
সলোমন

23

আপনার দুটি সিঙ্ক্রোনাইজড পদ্ধতি রয়েছে তবে এর মধ্যে একটি স্থিতিশীল এবং অন্যটি নয়। সিঙ্ক্রোনাইজড পদ্ধতিতে অ্যাক্সেস করার সময়, এর ধরণের (স্থিতিশীল বা অ-স্থিতিশীল) উপর ভিত্তি করে একটি পৃথক বস্তু লক হয়ে যাবে। একটি স্থিতিশীল পদ্ধতির জন্য, ক্লাস অবজেক্টে একটি লক রাখা হবে, যখন অ-স্থিতিশীল ব্লকের জন্য, পদ্ধতিটি চালিত শ্রেণীর উদাহরণে একটি লক স্থাপন করা হবে। আপনার দুটি পৃথক লক করা অবজেক্ট রয়েছে বলে আপনার দুটি থ্রেড থাকতে পারে যা একই সাথে একই জিনিসটিকে পরিবর্তন করে।


14

উপরের শ্রেণিটি থ্রেড নিরাপদ নয় কেন কেউ ব্যাখ্যা করতে পারেন?

  • increment স্থিতিশীল হওয়ার কারণে, সিঙ্ক্রোনাইজেশন ক্লাসেই করা হবে।
  • decrementস্থিতিশীল না হওয়ায় অবজেক্ট ইনস্ট্যান্টিয়েশনে সিঙ্ক্রোনাইজেশন করা হবে, তবে এটি countস্থির মতো কিছুই সুরক্ষিত করে না ।

থ্রেড-নিরাপদ কাউন্টার ঘোষণার জন্য আমি এটি যুক্ত করতে চাই, আমি বিশ্বাস করি যে AtomicIntegerআদিম অন্তরের পরিবর্তে সবচেয়ে সহজ উপায়টি ব্যবহার করা।

আমাকে আপনাকে java.util.concurrent.atomicপ্যাকেজ- তথ্যে পুনর্নির্দেশ দিন ।


7

অন্যের উত্তরগুলি কারণটির ব্যাখ্যা দিয়ে বেশ ভাল। আমি সংক্ষেপে কিছু যুক্ত করেছি synchronized:

public class A {
    public synchronized void fun1() {}

    public synchronized void fun2() {}

    public void fun3() {}

    public static synchronized void fun4() {}

    public static void fun5() {}
}

A a1 = new A();

synchronizedচালু fun1এবং fun2উদাহরণ বস্তু স্তরে সিঙ্ক্রোনাইজ করা হয়। synchronizedউপর fun4বর্গ বস্তুর স্তরে সিঙ্ক্রোনাইজ করা হয়। যার অর্থ:

  1. যখন a1.fun1()একই সাথে 2 টি থ্রেড কল করবে, তখনকার কলটি ব্লক করা হবে।
  2. যখন থ্রেড 1 কল a1.fun1()এবং থ্রেড 2 কল a1.fun2()একই সাথে হবে, তারপরের কলটি অবরুদ্ধ করা হবে।
  3. থ্রেড 1 কল a1.fun1()এবং থ্রেড 2 কল a1.fun3()একই সময়ে, কোনও ব্লক করা নেই, 2 পদ্ধতি একই সময়ে কার্যকর করা হবে।
  4. যখন 1 কল থ্রেড A.fun4(), যদি অন্যান্য থ্রেড কল A.fun4()বা A.fun5()একই সময়ে আধুনিক কল ব্লক করা হবে যেহেতু synchronizedউপর fun4বর্গ স্তর।
  5. থ্রেড 1 কল A.fun4(), থ্রেড 2 কল a1.fun1()একই সাথে, কোনও ব্লক করা নেই, 2 পদ্ধতি একই সময়ে কার্যকর করা হবে।

6
  1. decrementincrementতারা একে অপরকে দৌড়াদৌড়ি থেকে আটকাবে না সেজন্য একটি আলাদা জিনিসকে লক করছে।
  2. কল করা হচ্ছে decrementএক উদাহরণ হিসেবে বলা যায় কলিং একটি ভিন্ন জিনিস লক করা হয় decrementএবং অন্য দিকে, কিন্তু তারা একই জিনিস প্রভাবিত করছে।

প্রথমটির অর্থ হ'ল ওভারল্যাপিংয়ে কল করা incrementএবং decrementফলস্বরূপ একটি বাতিল-আউট (সঠিক), ইনক্রিমেন্ট বা হ্রাস হতে পারে।

দ্বিতীয়টির অর্থ হল যে decrementবিভিন্ন পরিস্থিতিতে দুটি ওভারল্যাপিং কলগুলি ডাবল হ্রাস (সঠিক) বা একক হ্রাস পেতে পারে।


4

যেহেতু দুটি পৃথক পৃথক পদ্ধতি রয়েছে, একটির উদাহরণ স্তর এবং অন্যটি শ্রেণির স্তর, সুতরাং এটি থ্রেডসেফ তৈরি করতে আপনাকে 2 টি পৃথক বস্তু লক করতে হবে


1

অন্যান্য উত্তরে বর্ণিত হিসাবে, আপনার কোডটি থ্রেড নিরাপদ নয় যেহেতু স্ট্যাটিক পদ্ধতি increment()লক করে ক্লাস মনিটর এবং অ-স্থিতিক পদ্ধতিতে decrement()লজ অবজেক্ট মনিটর।

এই কোড উদাহরণের জন্য, synchronzedকীওয়ার্ড ব্যবহার না করে আরও ভাল সমাধান বিদ্যমান । থ্রেড সুরক্ষা অর্জন করতে আপনাকে অ্যাটমিকআইন্টিজার ব্যবহার করতে হবে।

থ্রেড নিরাপদ ব্যবহার করে AtomicInteger:

import java.util.concurrent.atomic.AtomicInteger;

class ThreadSafeClass extends Thread {

    private static AtomicInteger count = new AtomicInteger(0);

    public static void increment() {
        count.incrementAndGet();
    }

    public static void decrement() {
        count.decrementAndGet();
    }

    public static int value() {
        return count.get();
    }

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.