জাভা সিঙ্ক্রোনাইজড পদ্ধতিতে লক অবজেক্ট, বা পদ্ধতিতে?


191

যদি আমার একই শ্রেণিতে 2 টি সিঙ্ক্রোনাইজড পদ্ধতি থাকে তবে প্রতিটি পৃথক ভেরিয়েবল অ্যাক্সেস করে তবে 2 থ্রেডগুলি একই সময়ে সেই 2 টি পদ্ধতিতে অ্যাক্সেস করতে পারে? লকটি কি বস্তুটিতে উপস্থিত হয়, বা এটি সিঙ্ক্রোনাইজড পদ্ধতির অভ্যন্তরে ভেরিয়েবলগুলির মতো নির্দিষ্ট হয়ে যায়?

উদাহরণ:

class X {

    private int a;
    private int b;

    public synchronized void addA(){
        a++;
    }

    public synchronized void addB(){
        b++;
    }

}

দ্বাদশ শ্রেণি একই সাথে দশম শ্রেণীর পারফর্ম করার ক্ষেত্রে একই অ্যাক্সেস অ্যাক্সেস করতে পারে x.addA() এবং x.addB()একই সাথে?

উত্তর:


197

আপনি যদি পদ্ধতিটিকে সিঙ্ক্রোনাইজ হিসাবে ঘোষণা করেন (যেমন আপনি টাইপ করে যাচ্ছেন public synchronized void addA()) আপনি পুরো অবজেক্টে সিঙ্ক্রোনাইজ করেছেন , সুতরাং এই একই অবজেক্ট থেকে আলাদা ভেরিয়েবল অ্যাক্সেস করার জন্য দুটি থ্রেড যাইহোক একে অপরকে অবরুদ্ধ করবে।

আপনি যদি একবারে কেবলমাত্র একটি ভেরিয়েবলের সাথে সিঙ্ক্রোনাইজ করতে চান, সুতরাং দুটি চলক বিভিন্ন ভেরিয়েবল অ্যাক্সেস করার সময় একে অপরকে অবরুদ্ধ করবে না, আপনি synchronized ()ব্লকগুলিতে পৃথক করে সেগুলিতে সিঙ্ক্রোনাইজ করেছেন । যদি abঅবজেক্ট রেফারেন্স হত তবে আপনি ব্যবহার করবেন:

public void addA() {
    synchronized( a ) {
        a++;
    }
}

public void addB() {
    synchronized( b ) {
        b++;
    }
}

তবে যেহেতু তারা আদিম, আপনি এটি করতে পারবেন না।

আমি আপনাকে পরিবর্তে অ্যাটমিকআইন্টিজার ব্যবহার করার পরামর্শ দিচ্ছি :

import java.util.concurrent.atomic.AtomicInteger;

class X {

    AtomicInteger a;
    AtomicInteger b;

    public void addA(){
        a.incrementAndGet();
    }

    public void addB(){ 
        b.incrementAndGet();
    }
}

181
আপনি যদি পদ্ধতিটিতে সিঙ্কনাইজ করেন তবে আপনি পুরো বস্তুটি লক করে রেখেছেন, সুতরাং এই একই বস্তু থেকে পৃথক ভেরিয়েবল অ্যাক্সেস করা দুটি থ্রেড যাইহোক একে অপরকে অবরুদ্ধ করবে। এটি কিছুটা বিভ্রান্তিকর। পদ্ধতির সাথে সিঙ্ক্রোনাইজ করা কার্যত synchronized (this)দেহের চারপাশে একটি ব্লক থাকার সমতুল্য । "এই" অবজেক্টটি লক হয়ে যায় না, বরং "এই" অবজেক্টটি "মিটেক্স" হিসাবে ব্যবহৃত হয় এবং শরীরকে একই সাথে অন্যান্য কোড বিভাগগুলির সাথে "এটিতে সিঙ্ক্রোনাইজ করা থেকে রক্ষা করা হয়।" এটি "এটি" এর অন্যান্য ক্ষেত্র / পদ্ধতিগুলিতে কোনও প্রভাব ফেলবে না যা সিঙ্ক্রোনাইজ করা হয়নি।
মার্ক পিটারস

13
হ্যাঁ, এটি সত্যই বিভ্রান্তিকর। প্রকৃত উদাহরণ হিসাবে - এটি দেখুন - stackoverflow.com/questions/14447095/… - সংক্ষিপ্তসার: লক করা কেবল সিঙ্ক্রোনাইজড পদ্ধতি স্তরে এবং অবজেক্টের উদাহরণ ভেরিয়েবলগুলি অন্য থ্রেড দ্বারা অ্যাক্সেস করা যায়
ম্যাক

5
প্রথম উদাহরণটি মূলত ভাঙ্গা। যদি aএবং bঅবজেক্টস ছিল, যেমন Integerগুলি, অপারেটর প্রয়োগ করার সময় আপনি বিভিন্ন বিষয়গুলির সাথে প্রতিস্থাপন করছেন এমন পরিস্থিতিতে সিঙ্ক্রোনাইজ করছিলেন ++
হলগার

আপনার উত্তরটি ঠিক করুন এবং অ্যাটমিকআইন্টিজার সূচনা করুন: AtomicInteger a = new AtomicInteger (0);
মেহেদি

: হয়তো এই anwser সঙ্গে আপডেট করা উচিত বস্তুর নিজেই সিঙ্ক্রোনাইজ সম্পর্কে এই অন্যটি ব্যাখ্যা stackoverflow.com/a/10324280/1099452
lucasvc

71

পদ্ধতি ঘোষণায় সিঙ্ক্রোনাইজ করা হ'ল এটির জন্য সিনট্যাক্টিকাল চিনি:

 public void addA() {
     synchronized (this) {
          a++;
     }
  }

একটি স্থিতিশীল পদ্ধতিতে এটি এর জন্য সিনট্যাকটিকাল চিনি:

 ClassA {
     public static void addA() {
          synchronized(ClassA.class) {
              a++;
          }
 }

আমি মনে করি জাভা ডিজাইনাররা যদি জানতেন যে এখন সিঙ্ক্রোনাইজেশন সম্পর্কে কী বোঝা যায়, তারা সিনট্যাকটিকাল চিনি যুক্ত না করতেন, কারণ এটি প্রায়শই সম্মতিযুক্ত খারাপ প্রয়োগের দিকে পরিচালিত করে না।


3
সত্য না. সিঙ্ক্রোনাইজড পদ্ধতি সিঙ্ক্রোনাইজড (অবজেক্ট) থেকে আলাদা বাইকোড উত্পন্ন করে। কার্যকারিতা সমতুল্য হলেও এটি কেবল সিনট্যাকটিক চিনির চেয়ে বেশি।
স্টিভ কুও

10
আমি মনে করি না যে "সিনট্যাকটিকাল সুগার" কঠোরভাবে বাইট-কোড সমতুল্য হিসাবে সংজ্ঞায়িত হয়েছে। মুল বক্তব্যটি এটি কার্যত সমতুল্য।
যিশাই

1
যদি জাভা ডিজাইনাররা মনিটরদের সম্পর্কে ইতিমধ্যে যা জানা ছিল তা যদি জানতেন তবে তাদের মূলত ইউনিক্সের আভ্যন্তরীণ স্থানগুলি অনুকরণ করার পরিবর্তে এটি অন্যরকমভাবে করা উচিত ছিল। পের ব্রিঞ্চ হানসেন যখন জাভা চুক্তির আদিমতা দেখেছিলেন তখন তিনি বলেছিলেন 'স্পষ্টত আমি বৃথা হয়ে গেছি'
12:25

এটা সত্য. ওপি দ্বারা প্রদত্ত উদাহরণটি প্রতিটি পদ্ধতি লক করে প্রদর্শিত হবে তবে বাস্তবে তারা সকলেই একই বস্তুতে লক করে। খুব ছলচাতুর বাক্য গঠন। 10+ বছর জাভা ব্যবহার করার পরে আমি এটি জানতাম না। সুতরাং আমি এই কারণে সিঙ্ক্রোনাইজড পদ্ধতিগুলি এড়াতে চাই। আমি সর্বদা ভেবেছিলাম যে প্রতিটি পদ্ধতির জন্য সিঙ্ক্রোনাইজড সংজ্ঞাযুক্ত একটি অদৃশ্য বস্তু তৈরি হয়েছিল।
পিটার কুইরিং

21

সিঙ্ক্রোনাইজড পদ্ধতিতে "জাভা ™ টিউটোরিয়ালস" থেকে :

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

সিঙ্ক্রোনাইজড ব্লকের "জাভা ™ টিউটোরিয়ালস" থেকে :

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

(জোর আমার)

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

public class MsLunch {

    private long c1 = 0;
    private long c2 = 0;

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

14

অ্যাক্সেস করা লকটি বস্তুটিতে রয়েছে, পদ্ধতিতে নয়। পদ্ধতির মধ্যে কোন ভেরিয়েবল অ্যাক্সেস করা হয় তা অপ্রাসঙ্গিক।

পদ্ধতিতে "সিঙ্ক্রোনাইজড" যুক্ত করার অর্থ কোড চালিত থ্রেডটি এগিয়ে যাওয়ার আগে অবশ্যই অবজেক্টের লকটি অর্জন করতে হবে। "স্ট্যাটিক সিঙ্ক্রোনাইজড" যুক্ত করার অর্থ কোডটি চালিত থ্রেডটি এগিয়ে যাওয়ার আগে অবশ্যই ক্লাস অবজেক্টের লকটি অর্জন করতে হবে। বিকল্পভাবে আপনি এই জাতীয় ব্লকটিতে কোডটি মোড়ানো করতে পারেন:

public void addA() {
    synchronized(this) {
        a++;
    }
}

যাতে আপনি সেই অবজেক্টটি নির্দিষ্ট করতে পারেন যার লকটি অবশ্যই অর্জন করা উচিত।

আপনি যদি ধারণকৃত বস্তুকে লক করা এড়াতে চান তবে আপনি এইগুলির মধ্যে চয়ন করতে পারেন:


7

ওরাকল ডকুমেন্টেশন লিঙ্ক থেকে

পদ্ধতিগুলি সিঙ্ক্রোনাইজড করার দুটি প্রভাব রয়েছে:

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

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

অভ্যন্তরীণ লক এবং লক আচরণ বুঝতে এই ডকুমেন্টেশন পৃষ্ঠাটিতে একবার দেখুন at

এটি আপনার প্রশ্নের জবাব দেবে: যখন একই সিঙ্ক্রোনাইজড মেথডগুলির মধ্যে একটি কার্যকর হওয়ার সময় আপনি একই সময়ে x.addA () এবং x.addB () কল করতে পারবেন না।


4

আপনার যদি এমন কিছু পদ্ধতি থাকে যা সিঙ্ক্রোনাইজ হয় না এবং অ্যাক্সেস করে ইনস্ট্যান্স ভেরিয়েবল পরিবর্তন করে। আপনার উদাহরণে:

 private int a;
 private int b;

যে কোনও সংখ্যক থ্রেড একই সময়ে এই অ-সিঙ্ক্রোনাইজড পদ্ধতিগুলিতে অ্যাক্সেস করতে পারে যখন অন্যান্য থ্রেড একই বস্তুর সিঙ্ক্রোনাইজ পদ্ধতিতে থাকে এবং উদাহরণ ভেরিয়েবলগুলিতে পরিবর্তন আনতে পারে। যেমন: -

 public void changeState() {
      a++;
      b++;
    }

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

নীচের দৃশ্যে: -

class X {

        private int a;
        private int b;

        public synchronized void addA(){
            a++;
        }

        public synchronized void addB(){
            b++;
        }
     public void changeState() {
          a++;
          b++;
        }
    }

থ্রেডগুলির মধ্যে কেবল একটিই অ্যাডএ বা অ্যাডবি পদ্ধতিতে হতে পারে তবে একই সাথে যে কোনও সংখ্যক থ্রেড চেঞ্জস্টেট পদ্ধতিতে প্রবেশ করতে পারে। কোনও দুটি থ্রেড একই সময়ে অ্যাডএ এবং অ্যাডবিতে প্রবেশ করতে পারে না (অবজেক্ট লেভেল লক হওয়ার কারণে) তবে একই সাথে যে কোনও সংখ্যক থ্রেড চেঞ্জস্টেটে প্রবেশ করতে পারে।


3

আপনি নিম্নলিখিত মত কিছু করতে পারেন। এই ক্ষেত্রে আপনি "এই" তে লকটির পরিবর্তে সিঙ্ক্রোনাইজ করার জন্য a এবং b এ লকটি ব্যবহার করছেন। আমরা ইনট ব্যবহার করতে পারি না কারণ আদিম মানেরগুলিতে লক নেই, তাই আমরা পূর্ণসংখ্যা ব্যবহার করি।

class x{
   private Integer a;
   private Integer b;
   public void addA(){
      synchronized(a) {
         a++;
      }
   }
   public synchronized void addB(){
      synchronized(b) {
         b++;
      }
   }
}

3

হ্যাঁ, এটা অন্যান্য পদ্ধতি অবরুদ্ধ করবে কারণ সিঙ্ক্রোনাইজ পদ্ধতি প্রযোজ্য গোটা সরু যেমন বর্গ বস্তুর .... কিন্তু যাহাই হউক না কেন এটি অন্যান্য থ্রেড সঞ্চালনের অবরুদ্ধ করবে শুধুমাত্র সমষ্টি যাই হোক না কেন পদ্ধতি adda বা addB এটা প্রবেশ করে, কারণ যখন এটি সমাপ্ত করণ যখন ... একটি থ্রেড অবজেক্টকে ফ্রি করবে এবং অন্য থ্রেডটি অন্য পদ্ধতিতে অ্যাক্সেস করবে এবং পুরোপুরি কাজ করবে।

আমি বোঝাতে চাইছি "সিঙ্ক্রোনাইজড" নির্দিষ্ট কোড প্রয়োগের সময় অন্য থ্রেডটিকে অন্য অ্যাক্সেস থেকে আটকাতে অবিকল তৈরি করা হয়েছে। সুতরাং শেষ পর্যন্ত এই কোডটি ভাল কাজ করবে।

চূড়ান্ত দ্রষ্টব্য হিসাবে, যদি একটি 'ক' এবং 'বি' ভেরিয়েবল থাকে তবে কেবল একটি অনন্য ভেরিয়েবল 'এ' বা অন্য যে কোনও নাম নয়, এই পদ্ধতিগুলি সিঙ্ক্রোনাইজ করার দরকার নেই কারণ এটি সম্পূর্ণরূপে নিরাপদ অন্য বর্ণের অ্যাক্সেস করছে (অন্যান্য স্মৃতি অবস্থান)।

class X {

private int a;
private int b;

public void addA(){
    a++;
}

public void addB(){
    b++;
}}

পাশাপাশি কাজ করবে


2

এই উদাহরণটি (যদিও এটি বেশ সুন্দর নয়) লকিংয়ের প্রক্রিয়াটিতে আরও অন্তর্দৃষ্টি সরবরাহ করতে পারে। তাহলে incrementA হয় সিঙ্ক্রোনাইজ , এবং incrementB হয় সিঙ্ক্রোনাইজ করা , তারপর incrementB যত শীঘ্র সম্ভব মৃত্যুদন্ড কার্যকর করা হবে, কিন্তু যদি incrementB হয় সিঙ্ক্রোনাইজ তারপর এটি জন্য 'অপেক্ষা' থেকে হয়েছে incrementA আগে, শেষ পর্যন্ত incrementB তার কাজ করতে পারেন।

উভয় পদ্ধতিকে একক উদাহরণে বলা হয় - বস্তু, উদাহরণস্বরূপ এটি হ'ল: চাকরি এবং 'প্রতিযোগিতামূলক' থ্রেড একটি ট্র্যাড এবং মূল

ইনক্রিমেন্টবিতে এবং এটি ছাড়া ' সিঙ্ক্রোনাইজড ' দিয়ে চেষ্টা করুন এবং আপনি বিভিন্ন ফলাফল দেখতে পাবেন। যদি ইনক্রিমেন্টবি পাশাপাশি ' সিঙ্ক্রোনাইজড ' হয় তবে এটি ইনক্রিমেন্টএ () সমাপ্ত হওয়ার জন্য অপেক্ষা করতে হবে । প্রতিটি বৈকল্পিক কয়েকবার চালান।

class LockTest implements Runnable {
    int a = 0;
    int b = 0;

    public synchronized void incrementA() {
        for (int i = 0; i < 100; i++) {
            this.a++;
            System.out.println("Thread: " + Thread.currentThread().getName() + "; a: " + this.a);
        }
    }

    // Try with 'synchronized' and without it and you will see different results
    // if incrementB is 'synchronized' as well then it has to wait for incrementA() to finish

    // public void incrementB() {
    public synchronized void incrementB() {
        this.b++;
        System.out.println("*************** incrementB ********************");
        System.out.println("Thread: " + Thread.currentThread().getName() + "; b: " + this.b);
        System.out.println("*************** incrementB ********************");
    }

    @Override
    public void run() {
        incrementA();
        System.out.println("************ incrementA completed *************");
    }
}

class LockTestMain {
    public static void main(String[] args) throws InterruptedException {
        LockTest job = new LockTest();
        Thread aThread = new Thread(job);
        aThread.setName("aThread");
        aThread.start();
        Thread.sleep(1);
        System.out.println("*************** 'main' calling metod: incrementB **********************");
        job.incrementB();
    }
}

1

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


0

এটি হয়ত কাজ করবে না কারণ বক্সিং এবং অটোবক্সিংটি ইন্টিজার থেকে ইনট এবং বিপরীতমুখী জেভিএম এর উপর নির্ভরশীল এবং দুটি-পৃথক সংখ্যা -128 এবং 127 এর মধ্যে থাকলে একই ঠিকানায় হ্যাশ হওয়ার সম্ভাবনা রয়েছে।

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