জাভা 8 ইন্টারফেস পদ্ধতিতে "সিঙ্ক্রোনাইজড" না হওয়ার কারণ কী?


210

জাভা 8-তে, আমি সহজেই লিখতে পারি:

interface Interface1 {
    default void method1() {
        synchronized (this) {
            // Something
        }
    }

    static void method2() {
        synchronized (Interface1.class) {
            // Something
        }
    }
}

আমি সম্পূর্ণ সিঙ্ক্রোনাইজেশন শব্দার্থকগুলি পেয়ে যাব যা আমি ক্লাসেও ব্যবহার করতে পারি। আমি তবে synchronizedপদ্ধতি ঘোষণায় পরিবর্তকটি ব্যবহার করতে পারি না :

interface Interface2 {
    default synchronized void method1() {
        //  ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
    }

    static synchronized void method2() {
        // ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
    }
}

এখন, কেউ তর্ক করতে পারে যে দুটি ইন্টারফেস একইরকম আচরণ করে যা ব্যতীত Interface2একটি চুক্তি প্রতিষ্ঠিত করে method1()এবং method2()যা কিছু Interface1করে তার চেয়ে কিছুটা শক্ত । অবশ্যই, আমরা এটিও যুক্তিযুক্ত হতে পারি যে defaultবাস্তবায়নগুলি কংক্রিট বাস্তবায়ন রাষ্ট্র সম্পর্কে কোনও অনুমান করা উচিত নয়, বা এই জাতীয় কীওয়ার্ডটি কেবল তার ওজনকে টানবে না।

প্রশ্ন:

জেএসআর -৩৩৫ বিশেষজ্ঞ গ্রুপ কেন synchronizedইন্টারফেস পদ্ধতিতে সমর্থন না করার সিদ্ধান্ত নিয়েছে ?


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

@ মার্টিন স্ট্রেজসি: এটি বাদ দেওয়ার জন্য ব্যাখ্যা হতে পারে default synchronized, তবুও অগত্যা নয় static synchronized, যদিও আমি মেনে নেব যে ধারাবাহিকতার কারণে পরবর্তীকালে বাদ দেওয়া যেতে পারে।
লুকাশ ইডার

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

@ স্কিভি: ওভাররাইডিং যুক্তি যথেষ্ট নয়। সাবক্লাসগুলি synchronizedকার্যকর পদ্ধতিতে সিঙ্ক্রোনাইজেশন অপসারণ করে সুপার ক্লাসে ঘোষিত পদ্ধতিগুলিকে ওভাররাইড করতে পারে । আমি বিস্মিত হবে না যে সমর্থন না synchronizedএবং সমর্থন না finalসম্পর্কযুক্ত, যদিও, হয়তো একাধিক উত্তরাধিকার কারণে (যেমন inheriting void x() এবং synchronized void x() , ইত্যাদি)। তবে তা জল্পনা। আমি একটি অনুমোদিত কারণ সম্পর্কে কৌতূহল, যদি এটি আছে।
লুকাস এদার

2
>> "সাবক্লাসগুলি এমন পদ্ধতিগুলিকে ওভাররাইড করতে পারে যা সুপার ক্লাসগুলিতে সিঙ্ক্রোনাইজড ঘোষণা করা হয়, কার্যকরভাবে সিঙ্ক্রোনাইজেশন মুছে ফেলা হয়" ... কেবলমাত্র যদি তারা কল না করে superযার জন্য পুনরায় বাস্তবায়নের প্রয়োজন হয় এবং ব্যক্তিগত সদস্যদের সম্ভাব্য অ্যাক্সেসের প্রয়োজন হয়। বিটিডব্লু, এই পদ্ধতিগুলিকে "ডিফেন্ডার" বলা হওয়ার একটি কারণ রয়েছে - তারা সহজেই নতুন পদ্ধতি যুক্ত করার অনুমতি দেওয়ার জন্য উপস্থিত রয়েছে।
বেটসেস

উত্তর:


260

প্রথমদিকে এটি স্পষ্ট মনে হতে পারে যে কেউ synchronizedডিফল্ট পদ্ধতিতে সংশোধককে সমর্থন করতে চায় তবে দেখা যায় যে এটি করা বিপজ্জনক হবে এবং তাই নিষিদ্ধ ছিল।

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

তাহলে, তারা কেন বিপজ্জনক? সিঙ্ক্রোনাইজেশন লক করা সম্পর্কে। লক করা পরিবর্তনীয় স্থিতিতে ভাগ করে নেওয়া অ্যাক্সেসের সমন্বয় সম্পর্কে। প্রতিটি অবজেক্টের একটি সিঙ্ক্রোনাইজেশন নীতি থাকতে হবে যা নির্ধারণ করে যে কোন লকটি কোন রাজ্যের ভেরিয়েবলগুলি রক্ষা করে। ( অনুশীলনে জাভা কনকুরન્સી দেখুন , বিভাগ ২.৪।)

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

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

একক উত্স ফাইলের জন্য ধারাবাহিকভাবে একটি সিঙ্ক্রোনাইজেশন নীতি বজায় রাখা যথেষ্ট ইতিমধ্যে শক্ত; একটি সাবক্লাস তার সুপারক্লাস দ্বারা সংজ্ঞায়িত সিঙ্ক্রোনাইজেশন নীতিটি সঠিকভাবে মেনে চলেছে তা নিশ্চিত করা আরও শক্ত। এ জাতীয় আলগাভাবে সংযুক্ত ক্লাসগুলির (এমন একটি ইন্টারফেস এবং সম্ভবত এটি অনেকগুলি ক্লাস যা এটি প্রয়োগ করে) মধ্যে করার চেষ্টা করা প্রায় অসম্ভব এবং অত্যন্ত ত্রুটি-ঝুঁকির মধ্যে থাকবে।

All সমস্ত যুক্তির বিপরীতে দেওয়া হলে তার পক্ষে কী যুক্তি হবে? দেখে মনে হচ্ছে তারা বেশিরভাগ বৈশিষ্ট্যের মতো ইন্টারফেস তৈরির বিষয়ে making যদিও এটি একটি বোধগম্য আকাঙ্ক্ষা, তবুও ডিফল্ট পদ্ধতিগুলির জন্য নকশা কেন্দ্রটি ইন্টারফেস বিবর্তন, "ট্রেইট--" নয়। যেখানে দুটি ধারাবাহিকভাবে অর্জন করা যেতে পারে, আমরা তা করার চেষ্টা করেছি, তবে যেখানে একজনের সাথে অন্যের বিরোধ রয়েছে, সেখানে আমাদের প্রাথমিক নকশার লক্ষ্যটির পক্ষে বেছে নিতে হয়েছিল।


26
আরও লক্ষ করুন যে synchronizedজেডিকে ১.১-এ, পদ্ধতিটি সংশোধকটি জাভাদোক আউটপুটটিতে উপস্থিত হয়েছিল, লোকেদের ভেবে ভ্রষ্ট করেছিল যে এটি নির্দিষ্টকরণের অংশ। এটি জেডিকে ২.২ এ স্থির করা হয়েছিল। এমনকি যদি এটি সর্বজনীন পদ্ধতিতে প্রদর্শিত হয়, synchronizedপরিবর্তক চুক্তি নয়, বাস্তবায়নের অংশ। ( nativeসংশোধনকারীটির জন্য অনুরূপ যুক্তি এবং চিকিত্সা ঘটেছে ))
স্টুয়ার্ট মার্কস

15
প্রারম্ভিক জাভা প্রোগ্রামগুলিতে একটি সাধারণ ভুল ছিল synchronizedচারপাশে পর্যাপ্ত এবং থ্রেড নিরাপদ উপাদান ছিটানো এবং আপনার প্রায় থ্রেড নিরাপদ প্রোগ্রাম ছিল। সমস্যাটি হ'ল এটি সাধারণত ঠিক কাজ করেছিল তবে এটি আশ্চর্যজনক এবং ভঙ্গুর উপায়ে ভাঙা। আমি সম্মত হই যে আপনার লকিং কীভাবে কাজ করে তা বোঝা শক্তিশালী অ্যাপ্লিকেশনের মূল চাবিকাঠি।
পিটার লরে

10
@ ব্রায়ানগোয়েটস খুব ভাল কারণ তবে কেন synchronized(this) {...}কোনও defaultপদ্ধতিতে অনুমোদিত ? (যেমন লুকাসের প্রশ্নে দেখানো হয়েছে।) ডিফল্ট পদ্ধতিটিও বাস্তবায়ন শ্রেণীর রাষ্ট্রের মালিকানা পেতে দেয় না? আমরা কি তাও আটকাতে চাই না? অবিজ্ঞাত বিকাশকারীরা যে মামলাগুলি করে সেগুলি অনুসন্ধান করার জন্য আমাদের কি ফাইন্ডবস নিয়মের দরকার হবে?
জেফ্রি ডি স্মেট

17
@ জিফ্রে: না, এটি সীমাবদ্ধ করার কোনও কারণ নেই (যদিও এটি সর্বদা যত্ন সহ ব্যবহার করা উচিত)) সিঙ্ক ব্লকে লেখকের স্পষ্টভাবে একটি লক অবজেক্ট নির্বাচন করা প্রয়োজন; এটি তাদের যদি কোনও নীতিটি কী তা জেনে থাকে তবে যদি তারা অন্য কোনও বস্তুর সমন্বয় নীতিতে অংশ নিতে দেয়। বিপজ্জনক অংশটি ধরে নিচ্ছে যে 'এটি' (যা সিঙ্ক পদ্ধতিগুলি এটি করে) এর সাথে সিঙ্ক্রোনাইজ করা আসলে অর্থবহ; এটি আরও সুস্পষ্ট সিদ্ধান্ত নেওয়া দরকার। এটি বলেছিল, আমি আশা করি ইন্টারফেস পদ্ধতিতে সিঙ্ক ব্লকগুলি বেশ বিরল to
ব্রায়ান গয়েটজ

6
@ জিফ্রেডিসমেট: একই কারণে আপনি যেমন করতে পারেন synchronized(vector)। এটি আপনি নিরাপদ থাকতে চান, আপনার thisলক করার জন্য কখনও কোনও পাবলিক অবজেক্ট (যেমন নিজেই) ব্যবহার করা উচিত নয় ।
যোগু

0
public class ParentSync {

public synchronized void parentStart() {
    System.out.println("I am " + this.getClass() + " . parentStarting. now:" + nowStr());
    try {
        Thread.sleep(30000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("I am " + this.getClass() + " . parentFinished. now" + nowStr());
}

private String nowStr() {
    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
}


public class SonSync1 extends ParentSync {
public void sonStart() {
    System.out.println("I am " + this.getClass() + ". sonStarting,calling parent now ... ");
    super.parentStart();
    System.out.println("I am " + this.getClass() + ". sonFinished");
}
}



public class SonSync2 extends ParentSync {

public void sonStart() {
    System.out.println("I am " + this.getClass() + ". sonStarting,calling parent now ... ");
    super.parentStart();
    System.out.println("I am " + this.getClass() + ". sonFinished");
}
}



public class SyncTest {
public static void main(String[] args) throws Exception {

    new Thread(() -> {
        new SonSync1().sonStart();
    }).start();

    new Thread(() -> {
        new SonSync2().sonStart();
    }).start();

    System.in.read();
}
}

ফলাফল:

I am class com.common.interface18_design.whynotsync_onmethod.SonSync1. sonStarting,calling parent now ... 
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2. sonStarting,calling parent now ... 
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2 . parentStarting. now:2019-04-18 09:50:08
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1 . parentStarting. now:2019-04-18 09:50:08
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1 . parentFinished. now2019-04-18 09:50:38
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1. sonFinished
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2 . parentFinished. now2019-04-18 09:50:38
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2. sonFinished

(উদাহরণ হিসাবে অভিভাবক শ্রেণীর ব্যবহারের জন্য দুঃখিত)

ফলাফল থেকে, আমরা জানতে পারি যে প্যারেন্ট ক্লাস লকটি প্রতিটি উপ শ্রেণীর মালিকানাধীন, SonSync1 এবং SonSync2 অবজেক্টের আলাদা আলাদা অবজেক্ট লক রয়েছে। প্রতিটি লক স্বাধীনতা হয়। সুতরাং এই ক্ষেত্রে, আমি মনে করি এটি পিতামাতাদের ক্লাসে বা একটি সাধারণ ইন্টারফেসে সিঙ্ক্রোনাইজ করা বিপজ্জনক নয়। কেউ কি এই সম্পর্কে আরও ব্যাখ্যা করতে পারে?

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