! = চেক থ্রেডটি কি নিরাপদ?


140

আমি জানি যে যৌগিক ক্রিয়াকলাপগুলি যেমন i++থ্রেড নিরাপদ নয় কারণ তারা একাধিক ক্রিয়াকলাপ জড়িত ।

কিন্তু রেফারেন্সটি নিজেই একটি থ্রেড নিরাপদ অপারেশনটি পরীক্ষা করছে?

a != a //is this thread-safe

আমি এটি প্রোগ্রাম করার এবং একাধিক থ্রেড ব্যবহার করার চেষ্টা করেছি কিন্তু এটি ব্যর্থ হয়নি। আমার ধারণা আমি আমার মেশিনে রেস অনুকরণ করতে পারিনি could

সম্পাদনা করুন:

public class TestThreadSafety {
    private Object a = new Object();

    public static void main(String[] args) {

        final TestThreadSafety instance = new TestThreadSafety();

        Thread testingReferenceThread = new Thread(new Runnable() {

            @Override
            public void run() {
                long countOfIterations = 0L;
                while(true){
                    boolean flag = instance.a != instance.a;
                    if(flag)
                        System.out.println(countOfIterations + ":" + flag);

                    countOfIterations++;
                }
            }
        });

        Thread updatingReferenceThread = new Thread(new Runnable() {

            @Override
            public void run() {
                while(true){
                    instance.a = new Object();
                }
            }
        });

        testingReferenceThread.start();
        updatingReferenceThread.start();
    }

}

এই প্রোগ্রামটি আমি থ্রেড-সুরক্ষা পরীক্ষা করতে ব্যবহার করছি।

অদ্ভুত আচরণ

আমার প্রোগ্রামটি কিছু পুনরাবৃত্তির মধ্যে শুরু হওয়ার সাথে সাথে আমি আউটপুট ফ্ল্যাগের মান পাই, যার অর্থ রেফারেন্স !=চেক একই রেফারেন্সে ব্যর্থ। কিন্তু কিছু পুনরাবৃত্তির পরে আউটপুট স্থির মান হয়ে যায় falseএবং তারপরে দীর্ঘ সময় ধরে প্রোগ্রাম চালানো কোনও একক trueআউটপুট তৈরি করে না ।

আউটপুটটি কিছু এন (স্থির নয়) পুনরাবৃত্তির পরে যেমন প্রস্তাব দেয় তবে আউটপুট স্থির মান বলে মনে হয় এবং এটি পরিবর্তন হয় না।

আউটপুট:

কিছু পুনরাবৃত্তির জন্য:

1494:true
1495:true
1496:true
19970:true
19972:true
19974:true
//after this there is not a single instance when the condition becomes true

2
এই প্রসঙ্গে "থ্রেড-সেফ" বলতে আপনার অর্থ কী? আপনি কি জিজ্ঞাসা করছেন যে এটি সর্বদা মিথ্যা ফেরত দেওয়ার গ্যারান্টিযুক্ত?
জেবি নিজেট

@ জেবিনিজেট হ্যাঁ এটাই আমি ভাবছিলাম।
নরেন্দ্র পাঠাই

5
এটি সর্বদা একক থ্রেডযুক্ত প্রসঙ্গেও মিথ্যা ফেরায় না। এটি কোনও NaN হতে পারে ..
হেরোলেড

4
সম্ভাব্য ব্যাখ্যা: কোডটি কেবলমাত্র সময়েই সংকলিত হয়েছিল এবং সংকলিত কোডটি কেবল একবার ভেরিয়েবল লোড করে। এটি প্রত্যাশিত
মার্কো টপলনিক

3
পৃথক ফলাফল মুদ্রণ করা দৌড়গুলির জন্য পরীক্ষা করার একটি দুর্বল উপায়। মুদ্রণ (ফলাফলের বিন্যাসকরণ এবং ফলাফল উভয়ই) আপনার পরীক্ষার তুলনায় তুলনামূলকভাবে ব্যয়বহুল (এবং কখনও কখনও আপনার প্রোগ্রামটি টার্মিনাল বা টার্মিনালের সাথে সংযোগের ব্যান্ডউইথটি ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে থাকে) write এছাড়াও, আইওতে প্রায়শই নিজস্ব নিজস্ব মিটেক্স থাকে যা আপনার থ্রেডের সম্পাদনের আদেশকে অনুমতি দেবে (আপনার স্বতন্ত্র রেখাগুলি 1234:trueকখনই একে অপরের উপর আঘাত না করে ) নোট করুন । একটি রেস টেস্টের জন্য আরও কঠোর অভ্যন্তরীণ লুপ দরকার। শেষে একটি সংক্ষিপ্তসার মুদ্রণ করুন (যেমন কেউ একটি ইউনিট পরীক্ষার কাঠামোর সাথে নীচে করেছেন)।
বেন জ্যাকসন

উত্তর:


124

সিঙ্ক্রোনাইজের অভাবে এই কোড

Object a;

public boolean test() {
    return a != a;
}

উত্পাদন করতে পারে true। এটি বাইটকোডের জন্যtest()

    ALOAD 0
    GETFIELD test/Test1.a : Ljava/lang/Object;
    ALOAD 0
    GETFIELD test/Test1.a : Ljava/lang/Object;
    IF_ACMPEQ L1
...

যেহেতু আমরা দেখতে পাচ্ছি যে এটি aদুটি স্থানীয় ক্ষেত্রের জন্য ফিল্ড লোড করে, এটি একটি অ-পারমাণবিক অপারেশন, যদি aএর মধ্যে পরিবর্তিত হয় অন্য থ্রেডের তুলনা হতে পারে false

এছাড়াও, মেমোরি ভিজিবিলিটি সমস্যা এখানে প্রাসঙ্গিক, কোনও গ্যারান্টি নেই যে aঅন্য থ্রেডের দ্বারা করা পরিবর্তনগুলি বর্তমান থ্রেডে দৃশ্যমান হবে।


22
যদিও দৃ strong় প্রমাণ, বাইটকোড আসলে প্রমাণ নয়। এটি অবশ্যই
জেএলএসের

10
@ মারকো আমি আপনার চিন্তাভাবনার সাথে একমত, তবে অগত্যা আপনার সিদ্ধান্তে শেষ হওয়া উচিত। আমার কাছে উপরের বাইটকোডটি বাস্তবায়নের সুস্পষ্ট / আধ্যাত্মিক উপায় !=, যার মধ্যে এলএইচএস এবং আরএইচএস পৃথকভাবে লোড করা জড়িত। এবং তাই, যদি এলএইচএস এবং আরএইচএস সিন্টেক্সটিকভাবে অভিন্ন হয়, তখন জেএলএস অপ্টিমাইজেশন সম্পর্কিত নির্দিষ্ট কিছু উল্লেখ না করে , তবে সাধারণ নিয়ম প্রয়োগ হবে, যার অর্থ aদুইবার বোঝা ।
আন্দ্রেজেজ ডয়েল

20
প্রকৃতপক্ষে, ধরে নেওয়া যে উত্পন্ন বাইটোকডটি জেএলএসের সাথে সঙ্গতিপূর্ণ, এটি একটি প্রমাণ!
প্রসকর

6
@ অ্যাড্রিয়ান: প্রথমত: এমনকি এই অনুমানটি অবৈধ হলেও এমন একক সংকলকের উপস্থিতি যেখানে এটি "সত্য" এর মূল্যায়ন করতে পারে তা প্রমাণ করার জন্য যথেষ্ট যে এটি কখনও কখনও "সত্য" এর কাছে মূল্যায়ন করতে পারে (এমনকি যদি অনুমানটি নিষিদ্ধ করে - যা এটি না)। দ্বিতীয়ত: জাভাটি সুনির্দিষ্টভাবে নির্দিষ্ট, এবং বেশিরভাগ সংকলক এটির নিকটবর্তী হন। এগুলি তাদের এই ক্ষেত্রে একটি রেফারেন্স হিসাবে ব্যবহার করা বোধগম্য হয়। তৃতীয়ত: আপনি "জেআরই" শব্দটি ব্যবহার করেন তবে আমার মনে হয় না যে এটির অর্থ কী। । ।
রুখ

2
@ আলেকজান্ডারস্টলস্লিং - "যদিও আমি নিশ্চিত নই যে এটি একক-পঠিত অপ্টিমাইজেশনকে বাদ দেওয়ার পক্ষে যথেষ্ট কিনা"। এটি যথেষ্ট নয়। প্রকৃতপক্ষে, সিঙ্ক্রোনাইজেশনের অভাবে (এবং যে সম্পর্কগুলি আরোপ করে "এর আগে অতিরিক্ত" ঘটে যায়), অপ্টিমাইজেশনটি বৈধ,
স্টিফেন সি

47

চেক a != aথ্রেড-নিরাপদ?

যদি aঅন্য থ্রেডের দ্বারা যথাযথভাবে আপডেট করা যায় (যথাযথ সিঙ্ক্রোনাইজেশন ছাড়াই!), তবে না No.

আমি এটি প্রোগ্রাম করার এবং একাধিক থ্রেড ব্যবহার করার চেষ্টা করেছি কিন্তু ব্যর্থ হই নি। আমার অনুমান আমার মেশিনে রেস অনুকরণ করতে পারে না।

তার মানে কিছু নয়! সমস্যাটি হ'ল যদি কোনও নির্বাহকে aঅন্য থ্রেড দ্বারা আপডেট করা হয় জেএলএস দ্বারা অনুমোদিত হয় তবে কোডটি থ্রেড-নিরাপদ নয়। আপনি কোনও নির্দিষ্ট মেশিনে এবং কোনও নির্দিষ্ট জাভা প্রয়োগের ক্ষেত্রে একটি নির্দিষ্ট টেস্ট-কেসের সাথে দৌড়ের অবস্থার কারণ হতে না পারার বিষয়টি অন্য পরিস্থিতিতে ঘটতে বাধা দেয় না।

এর মানে কি এই যে a! = A ফিরে আসতে পারে true?

হ্যাঁ, তত্ত্বগতভাবে, নির্দিষ্ট পরিস্থিতিতে।

বিকল্পভাবে, একই সাথে পরিবর্তিত হলেও a != aফিরে আসতে পারে।falsea


"অদ্ভুত আচরণ" সম্পর্কিত:

আমার প্রোগ্রামটি কিছু পুনরাবৃত্তির মধ্যে শুরু হওয়ার সাথে সাথে আমি আউটপুট ফ্ল্যাগের মান পাই, যার অর্থ রেফারেন্স! = চেক একই রেফারেন্সে ব্যর্থ হয়। কিন্তু কিছু পুনরাবৃত্তির পরে আউটপুট স্থির মানটি মিথ্যা হয়ে যায় এবং তারপরে দীর্ঘ সময় ধরে প্রোগ্রামটি কার্যকর করা একক সত্যিকারের আউটপুট তৈরি করে না।

এই "অদ্ভুত" আচরণটি নিম্নলিখিত প্রয়োগের দৃশ্যের সাথে সামঞ্জস্যপূর্ণ:

  1. প্রোগ্রামটি লোড হয়ে গেছে এবং জেভিএম বাইটোকডগুলি ব্যাখ্যা করতে শুরু করে। যেহেতু (যেমন আমরা জাভাপ আউটপুট থেকে দেখেছি) বাইটোকোড দুটি লোড করে, আপনি (স্পষ্টতই) রেসের অবস্থার ফলাফলগুলি মাঝে মাঝে দেখতে পান।

  2. একটি সময় পরে, কোডটি JIT সংকলক দ্বারা সংকলিত হয়। জেআইটি অপ্টিমাইজার লক্ষ্য করে যে একই মেমরি স্লট ( a) দুটি ভার একসাথে কাছাকাছি রয়েছে, এবং দ্বিতীয়টিকে দূরে অপ্টিমাইজ করে। (প্রকৃতপক্ষে, এমন একটি সুযোগ রয়েছে যে এটি পুরোপুরি পরীক্ষাটিকে অনুকূল করে ...)

  3. এখন আর দৌড়ের অবস্থাটি আর প্রকাশ পায় না, কারণ সেখানে দুটি বোঝা আর নেই।

নোট করুন যে জেএলএস জাভা প্রয়োগের জন্য যা করতে দেয় তার সাথে এই সমস্ত সামঞ্জস্যপূর্ণ।


@ ক্রিস এইভাবে মন্তব্য করেছেন:

দেখে মনে হচ্ছে এটি সি বা সি ++ প্রোগ্রামাররা "অপরিজ্ঞাত আচরণ" (বাস্তবায়ন নির্ভর) বলে। মনে হচ্ছে এর মতো কোণার ক্ষেত্রে জাভাতে কয়েকটি ইউবি হতে পারে।

জাভা মেমোরি মডেল ( জেএলএস 17.4 এ উল্লিখিত) পূর্বশর্তগুলির একটি সেট নির্দিষ্ট করে যার অধীনে একটি থ্রেড অন্য থ্রেড দ্বারা লিখিত মেমরির মানগুলি দেখার নিশ্চয়তা দেয়। যদি একটি থ্রেড অন্য একটি দ্বারা রচিত একটি পরিবর্তনীয় পড়ার চেষ্টা করে, এবং সেই পূর্ব শর্তগুলি সন্তুষ্ট না হয়, তবে সম্ভাব্য মৃত্যুদণ্ড কার্যকর করা যেতে পারে ... যার কয়েকটি ভুল হওয়ার সম্ভাবনা রয়েছে (অ্যাপ্লিকেশনগুলির প্রয়োজনীয়তার দৃষ্টিকোণ থেকে)। অন্য কথায়, সম্ভাব্য আচরণগুলির সেট (অর্থাত্ "সুগঠিত মৃত্যুদণ্ড কার্যকর করা" এর সেট) সংজ্ঞায়িত করা হয়, তবে এই আচরণগুলির মধ্যে কোনটি ঘটবে তা আমরা বলতে পারি না।

সংকলকটি লোডগুলি একত্রিত ও পুনঃক্রম করতে এবং কোডের শেষ প্রভাবটি একইরূপে সংরক্ষণ (এবং অন্যান্য জিনিসগুলি) সংরক্ষণের অনুমতি দেয়:

  • যখন একক থ্রেড দ্বারা নির্বাহ করা হয় এবং
  • যখন সঠিকভাবে সিঙ্ক্রোনাইজ করে বিভিন্ন থ্রেড দ্বারা সম্পাদিত হয় (মেমোরি মডেল অনুসারে)।

তবে কোডটি যদি সঠিকভাবে সিঙ্ক্রোনাইজ না হয় (এবং তাই "এর আগে ঘটে" সম্পর্কগুলি সুসংগঠিত মৃত্যুদন্ডের সেটকে যথেষ্ট পরিমাণে সীমাবদ্ধ করে না) সংকলককে বোঝা এবং স্টোরগুলিকে এমনভাবে পুনরায় অর্ডার করার অনুমতি দেওয়া হয় যা "ভুল" ফলাফল দেয়। (তবে এটি সত্যই বলেছেন যে প্রোগ্রামটি ভুল)


এর অর্থ কি a != aসত্য ফিরে আসতে পারে?
প্রকোস্ট

আমি বোঝাতে চেয়েছিলাম যে সম্ভবত আমার মেশিনে আমি অনুকরণ করতে পারি না যে উপরের কোডটি নন-থ্রেড নিরাপদ। সুতরাং এর পিছনে কোনও তাত্ত্বিক যুক্তি থাকতে পারে।
নরেন্দ্র পাঠাই

@ নরেন্দ্রপাথাই - আপনি এটি প্রদর্শন করতে না পারার কোনও তাত্ত্বিক কারণ নেই। সম্ভবত ব্যবহারিক কারণ রয়েছে ... বা সম্ভবত আপনি ভাগ্যবান হন নি।
স্টিফেন সি

আমি যে প্রোগ্রামটি ব্যবহার করছি তার সাথে আমার আপডেট হওয়া উত্তরটি পরীক্ষা করুন। চেকটি কখনও কখনও সত্য ফিরে আসে তবে আউটপুটে একটি অদ্ভুত আচরণ বলে মনে হয়।
নরেন্দ্র পাঠাই

1
@ নরেন্দ্রপথাই - আমার ব্যাখ্যা দেখুন।
স্টিফেন সি

27

পরীক্ষা-এনজি দিয়ে প্রমাণিত:

public class MyTest {

  private static Integer count=1;

  @Test(threadPoolSize = 1000, invocationCount=10000)
  public void test(){
    count = new Integer(new Random().nextInt());
    Assert.assertFalse(count != count);
  }

}

আমার কাছে 10 000 নিমন্ত্রণে 2 টি ব্যর্থ। সুতরাং কোন , এটা হয় না শংকা মুক্ত


6
আপনি সমতার জন্যও যাচাই করছেন না ... Random.nextInt()অংশটি অতিমাত্রায়। আপনি new Object()ঠিক পাশাপাশি পরীক্ষা করতে পারে ।
মার্কো টপলনিক

@ মার্কো টপলনিক দয়া করে আমি যে প্রোগ্রামটি ব্যবহার করছি তার সাথে আমার আপডেট হওয়া উত্তরটি পরীক্ষা করুন check চেকটি কখনও কখনও সত্য ফিরে আসে তবে আউটপুটে একটি অদ্ভুত আচরণ বলে মনে হয়।
নরেন্দ্র পাঠাই

1
একটি পার্শ্ব নোট, এলোমেলো-অবজেক্টগুলি সাধারণত পুনঃব্যবহার করা বোঝানো হয়, প্রতিবার যখন আপনার নতুন ইনট প্রয়োজন হয় তখন তৈরি হয় না।
সাইমন ফারসবার্গ

15

না এটা না. একটি তুলনা করার জন্য জাভা ভিএমকে অবশ্যই স্ট্যাকের সাথে তুলনা করতে দুটি মান রাখতে হবে এবং তুলনা নির্দেশটি চালনা করতে হবে (কোনটি "a" এর ধরণের উপর নির্ভর করে)।

জাভা ভিএম হতে পারে:

  1. "একটি" দুইবার পড়ুন, প্রত্যেককে স্ট্যাকের উপর রাখুন এবং তারপরে ফলাফলগুলি তুলনা করুন
  2. "একটি" কেবল একবার পড়ুন, এটি স্ট্যাকের উপর রাখুন, এটির সদৃশ করুন ("ডুপ" নির্দেশ) এবং তুলনা চালান
  3. এক্সপ্রেশনটি সম্পূর্ণভাবে মুছে ফেলুন এবং এর সাথে প্রতিস্থাপন করুন false

1 ম ক্ষেত্রে, অন্য থ্রেড দুটি রিডের মধ্যে "ক" এর মান পরিবর্তন করতে পারে।

কোন কৌশলটি বেছে নেওয়া হয়েছে তা জাভা সংকলক এবং জাভা রানটাইম (বিশেষত জেআইটি সংকলক) এর উপর নির্ভর করে। এমনকি এটি আপনার প্রোগ্রামের রানটাইম চলাকালীন পরিবর্তিত হতে পারে।

আপনি যদি ভেরিয়েবলটি কীভাবে অ্যাক্সেস করা হয় তা নিশ্চিত করতে চান তবে আপনাকে অবশ্যই এটি তৈরি করতে হবে volatile(একটি তথাকথিত "অর্ধেক স্মৃতি বাধা") বা একটি পূর্ণ স্মৃতি বাধা যুক্ত করুন ( synchronized)। আপনি কিছু উচ্চ স্তরের এপিআইও ব্যবহার করতে পারেন (যেমন AtomicIntegerজুনেদ আহসান দ্বারা উল্লিখিত)

থ্রেড সুরক্ষা সম্পর্কে বিশদ জানতে, জেএসআর 133 ( জাভা মেমোরি মডেল ) পড়ুন।


aহিসাবে ঘোষণা volatileএখনও মধ্যে দুটি পরিবর্তনের সম্ভাবনা সঙ্গে দুটি স্বতন্ত্র পাঠ বোঝানো হবে।
হলগার

6

এগুলি সমস্ত স্টিফেন সি দ্বারা ভালভাবে ব্যাখ্যা করা হয়েছে মজাদার জন্য, আপনি নিম্নলিখিত JVM পরামিতিগুলির সাথে একই কোডটি চালানোর চেষ্টা করতে পারেন:

-XX:InlineSmallCode=0

এটি জেআইটি দ্বারা করা অপ্টিমাইজেশন আটকাতে হবে (এটি হটস্পট 7 সার্ভারে করে) এবং আপনি দেখতে পাবেন true চিরকালের জন্য (আমি ২,০০,০০০ এ থামলাম তবে আমি মনে করি এটি এর পরেও অব্যাহত থাকবে)।

তথ্যের জন্য, নীচে JIT'ed কোড দেওয়া আছে। সত্য কথা বলতে গেলে, আমি পরীক্ষাটি পরীক্ষামূলকভাবে সম্পন্ন হয়েছে কিনা বা দুটি বোঝা কোথা থেকে এসেছে তা জানতে সাবলীলভাবে সমাবেশ পাঠ করি না। (লাইন 26 হল পরীক্ষা flag = a != aএবং 31 লাইনটি এর বন্ধনী বন্ধনী while(true))।

  # {method} 'run' '()V' in 'javaapplication27/TestThreadSafety$1'
  0x00000000027dcc80: int3   
  0x00000000027dcc81: data32 data32 nop WORD PTR [rax+rax*1+0x0]
  0x00000000027dcc8c: data32 data32 xchg ax,ax
  0x00000000027dcc90: mov    DWORD PTR [rsp-0x6000],eax
  0x00000000027dcc97: push   rbp
  0x00000000027dcc98: sub    rsp,0x40
  0x00000000027dcc9c: mov    rbx,QWORD PTR [rdx+0x8]
  0x00000000027dcca0: mov    rbp,QWORD PTR [rdx+0x18]
  0x00000000027dcca4: mov    rcx,rdx
  0x00000000027dcca7: movabs r10,0x6e1a7680
  0x00000000027dccb1: call   r10
  0x00000000027dccb4: test   rbp,rbp
  0x00000000027dccb7: je     0x00000000027dccdd
  0x00000000027dccb9: mov    r10d,DWORD PTR [rbp+0x8]
  0x00000000027dccbd: cmp    r10d,0xefc158f4    ;   {oop('javaapplication27/TestThreadSafety$1')}
  0x00000000027dccc4: jne    0x00000000027dccf1
  0x00000000027dccc6: test   rbp,rbp
  0x00000000027dccc9: je     0x00000000027dcce1
  0x00000000027dcccb: cmp    r12d,DWORD PTR [rbp+0xc]
  0x00000000027dcccf: je     0x00000000027dcce1  ;*goto
                                                ; - javaapplication27.TestThreadSafety$1::run@62 (line 31)
  0x00000000027dccd1: add    rbx,0x1            ; OopMap{rbp=Oop off=85}
                                                ;*goto
                                                ; - javaapplication27.TestThreadSafety$1::run@62 (line 31)
  0x00000000027dccd5: test   DWORD PTR [rip+0xfffffffffdb53325],eax        # 0x0000000000330000
                                                ;*goto
                                                ; - javaapplication27.TestThreadSafety$1::run@62 (line 31)
                                                ;   {poll}
  0x00000000027dccdb: jmp    0x00000000027dccd1
  0x00000000027dccdd: xor    ebp,ebp
  0x00000000027dccdf: jmp    0x00000000027dccc6
  0x00000000027dcce1: mov    edx,0xffffff86
  0x00000000027dcce6: mov    QWORD PTR [rsp+0x20],rbx
  0x00000000027dcceb: call   0x00000000027a90a0  ; OopMap{rbp=Oop off=112}
                                                ;*aload_0
                                                ; - javaapplication27.TestThreadSafety$1::run@2 (line 26)
                                                ;   {runtime_call}
  0x00000000027dccf0: int3   
  0x00000000027dccf1: mov    edx,0xffffffad
  0x00000000027dccf6: mov    QWORD PTR [rsp+0x20],rbx
  0x00000000027dccfb: call   0x00000000027a90a0  ; OopMap{rbp=Oop off=128}
                                                ;*aload_0
                                                ; - javaapplication27.TestThreadSafety$1::run@2 (line 26)
                                                ;   {runtime_call}
  0x00000000027dcd00: int3                      ;*aload_0
                                                ; - javaapplication27.TestThreadSafety$1::run@2 (line 26)
  0x00000000027dcd01: int3   

1
এটি যখন আপনার অসীম লুপ থাকে এবং সমস্ত কিছু কমবেশি উত্তোলন করা যায় তখন জেভিএম আসলে যে ধরণের কোড তৈরি করবে তার এটি একটি উদাহরণ example প্রকৃত "লুপ" এখানে থেকে তিনটি নির্দেশাবলী 0x27dccd1থেকে 0x27dccdfjmpলুপ নিঃশর্ত (যেহেতু লুপ অসীম যায়)। লুপের কেবলমাত্র দুটি নির্দেশাবলী add rbc, 0x1হ'ল - যা বৃদ্ধি পাচ্ছে countOfIterations(লুপটি কখনই বের হয় না সত্ত্বেও এই মানটি পড়বে না: সম্ভবত আপনি এটি ডিবাগারে ভাঙ্গলে ক্ষেত্রে এটি প্রয়োজন হয়), .. ।
BeeOnRope

... এবং অদ্ভুত সন্ধানের testনির্দেশ, যা আসলে কেবলমাত্র স্মৃতি অ্যাক্সেসের জন্য রয়েছে (নোটটি eaxএমনকি পদ্ধতিটিতে সেটও করা হয় না!): জেভিএম যখন সমস্ত থ্রেড ট্রিগার করতে চায় তখন এটি একটি বিশেষ পৃষ্ঠা যা পঠনযোগ্য নয় সেট করা হয় কোনও সাফাইপয়েন্টে পৌঁছাতে, যাতে এটি জিসি বা অন্য কোনও ক্রিয়াকলাপ করতে পারে যার জন্য সমস্ত থ্রেড একটি পরিচিত অবস্থায় থাকা প্রয়োজন।
BeeOnRope

আরও উল্লেখযোগ্যভাবে, JVM লুপটির instance. a != instance.aবাইরে তুলনা সম্পূর্ণভাবে উত্তোলন করেছে এবং লুপটি প্রবেশের আগে কেবল একবার এটি সম্পাদন করে! এটি জানে যে এটি পুনরায় লোড করার প্রয়োজন নেই instanceবা aসেগুলি অস্থির হিসাবে ঘোষিত হয়নি এবং অন্য কোনও কোড নেই যা তাদের একই থ্রেডে পরিবর্তন করতে পারে, সুতরাং এটি কেবল ধরে নেয় যে তারা পুরো লুপের সময় একই রকম, যা মেমোরি দ্বারা অনুমোদিত মডেল.
BeeOnRope

5

না, a != aথ্রেড নিরাপদ নয়। এই অভিব্যক্তিটি তিনটি অংশ নিয়ে গঠিত: লোড a, aআবার লোড করুন এবং সম্পাদন করুন !=। অন্য থ্রেডের পক্ষে aতার পিতামাতার অভ্যন্তরীণ লক অর্জন এবং a2 লোড ক্রিয়াকলাপের মধ্যে মানটির পরিবর্তন করা সম্ভব ।

যদিও অন্য একটি কারণ aস্থানীয় কিনা । যদি aস্থানীয় হয় তবে অন্য কোনও থ্রেডে এর অ্যাক্সেস থাকা উচিত নয় এবং তাই থ্রেডটি নিরাপদ হওয়া উচিত।

void method () {
    int a = 0;
    System.out.println(a != a);
}

সর্বদা মুদ্রণ করা উচিত false

ঘোষণা aযেমন volatileযদি জন্য সমস্যা সমাধানের না aহয় staticবা দৃষ্টান্ত। সমস্যাটি এই নয় যে থ্রেডের বিভিন্ন মান রয়েছে a, তবে এটি একটি থ্রেড aবিভিন্ন মান সহ দুবার লোড হয়। এটি প্রকৃতপক্ষে কেসটিকে কম থ্রেড-নিরাপদ করে তুলতে পারে .. যদি aতা না হয় volatileতবে aক্যাশে করা যেতে পারে এবং অন্য থ্রেডে পরিবর্তন ক্যাশেড মানটিকে প্রভাবিত করবে না।


এর সাথে আপনার উদাহরণটি synchronizedভুল: সেই কোডটি মুদ্রণের গ্যারান্টিযুক্ত হওয়ার জন্য false, সেট করা সমস্ত পদ্ধতিও aহতে synchronizedহবে।
ruakh

কেন এমন? যদি পদ্ধতিটি সিঙ্ক্রোনাইজ করা হয় তবে aপদ্ধতিটি সঞ্চালনের সময় অন্য কোনও থ্রেড কীভাবে পিতামাতার অভ্যন্তরীণ লক অর্জন করবে , মান নির্ধারণের জন্য প্রয়োজনীয় a
DoubleMx2

1
আপনার প্রাঙ্গণটি ভুল। আপনি কোনও বস্তুর ক্ষেত্রটি এর অভ্যন্তরীণ লকটি অর্জন না করে সেট করতে পারেন। জাভাটির ক্ষেত্রগুলি সেট করার আগে কোনও বস্তুর অভ্যন্তরীণ লক অর্জনের জন্য থ্রেডের প্রয়োজন হয় না।
রুখ

3

অদ্ভুত আচরণ সম্পর্কে:

যেহেতু ভেরিয়েবলটি aচিহ্নিত করা হয়নি volatile, তাই কোনও কোনও মুহুর্তে এটির aথ্রেড দ্বারা ক্যাশে দেওয়া হতে পারে। উভয়ই aএর a != aপরে ক্যাশেড সংস্করণ এবং সুতরাং সর্বদা একই (অর্থ flagএখন সর্বদা সর্বদা false)।


0

এমনকি সাধারণ পঠনও পারমাণবিক নয়। যদি 32-বিট জেভিএমগুলিতে aথাকে longএবং চিহ্নিত না থাকে তবে থ্রেড-নিরাপদ নয়।volatilelong b = a


উদ্বায়ী এবং পারমাণবিকতা সম্পর্কিত নয়। এমনকি যদি আমি কোনও অস্থির হিসাবে চিহ্নিত করি তবে এটি অ-পারমাণবিক হবে
নরেন্দ্র পাঠাই

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