জাভাতে কীভাবে সিঙ্ক্রোনাইজ করা স্ট্যাটিক পদ্ধতি কাজ করে এবং আমি এটি হাইবারনেট সত্তা লোড করার জন্য ব্যবহার করতে পারি?


179

যদি আমার কাছে স্থিতিশীল পদ্ধতি সহ একটি ব্যবহার শ্রেণি থাকে যা মৌলিক ডেটা অ্যাক্সেস সম্পন্ন করতে হাইবারনেট ফাংশনগুলিতে কল করবে। আমি ভাবছি synchronizedপদ্ধতিটি তৈরি করা থ্রেড-সুরক্ষা নিশ্চিত করার জন্য সঠিক পন্থা কিনা।

আমি এটি একই ডিবি উদাহরণটিতে তথ্যের অ্যাক্সেস রোধ করতে চাই। যাইহোক, আমি এখন নিশ্চিত হয়েছি যে getObjectByIdযখন কোনও নির্দিষ্ট শ্রেণীর দ্বারা ডাকা হয় তখন নিম্নলিখিত কোডটি সমস্ত শ্রেণির জন্য কল করা রোধ করে।

public class Utils {
     public static synchronized Object getObjectById (Class objclass, Long id) {
           // call hibernate class
         Session session = new Configuration().configure().buildSessionFactory().openSession();
         Object obj = session.load(objclass, id);
         session.close();
         return obj;
     }

     // other static methods
}

উত্তর:


136

স্থিতিশীল পদ্ধতিতে লকটিতে সিঙ্ক্রোনাইজ ব্যবহার করে আপনি শ্রেণি পদ্ধতি এবং বৈশিষ্ট্যগুলিকে সিঙ্ক্রোনাইজ করবেন (উদাহরণ পদ্ধতি এবং বৈশিষ্ট্যের বিপরীতে)

সুতরাং আপনার অনুমান সঠিক।

আমি ভাবছি যে পদ্ধতিটি সিঙ্ক্রোনাইজ করা থ্রেড-সুরক্ষা নিশ্চিত করার সঠিক পদ্ধতি।

আসলে তা না. পরিবর্তে আপনার আরডিবিএমএসকে সেই কাজটি করতে দেওয়া উচিত। তারা এই ধরণের জিনিসগুলিতে ভাল।

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

নিম্নলিখিত পরিস্থিতিতে কল্পনা করুন:

ক্লায়েন্ট এ এবং বি সারণি টিয়ের রেকর্ড এক্সে বিভিন্ন তথ্য সন্নিবেশ করানোর চেষ্টা করেছে

আপনার পদ্ধতির সাথে আপনি যে বিষয়টি পেয়ে যাচ্ছেন তা হ'ল ডিবিতে যেভাবেই ঘটবে, অন্যটির পরে একজনকে ডেকে আনা হয়েছে তা নিশ্চিত করা, কারণ আরডিবিএমএস তাদের একই সাথে A থেকে অর্ধেক তথ্য সন্নিবেশ করানো থেকে বিরত রাখবে । ফলাফল একই হবে তবে মাত্র 5 বার (বা আরও) ধীর হবে।

সম্ভবত হাইবারনেট ডকুমেন্টেশনের "লেনদেন এবং সমঝোতা" অধ্যায়টি একবার দেখে নেওয়া ভাল । বেশিরভাগ সময় আপনি সমস্যার সমাধানের চেষ্টা করছেন, ইতিমধ্যে সমাধান হয়েছে এবং আরও অনেক ভাল উপায়।


1
খুব সহায়ক উত্তর! ধন্যবাদ! সুতরাং হাইবারনেট "আশাবাদী লকিং" দ্বারা cnocurrency যত্ন নেয়। তাহলে কোনও ডেটা-অ্যাক্সেসের সামঞ্জস্যতা সমাধানের জন্য "সিঙ্ক্রোনাইজড" পদ্ধতিগুলি ব্যবহার করার দরকার নেই কেন ?? ডাটাবেসে ডেটা সংরক্ষণ না করা হলেই "সিঙ্ক্রোনাইজড" পদ্ধতিগুলি ব্যবহার করবেন ?? .. আপনি যখন তাদের ব্যবহার করবেন ??
টমেটো

1
1) আমি মনে করি খুব আশাবাদী লকিং ব্যবহার করার কিছু উপায় আছে। 2) না, আরডিবিএমএস সেই কাজটি করতে পারে। 3) একই সময়ে যদি একাধিক থ্রেড দ্বারা ডেটা অ্যাক্সেস করা হয়। ৪) দুটি থ্রেডে ডেটা ভাগ করতে হলে সিঙ্ক্রোনাইজেশন কার্যকর হয়। তাদের যদি প্রয়োজন না হয়, তবে আরও ভাল!
অস্কাররেজ

7
যে কোনও ফাস্টফুড রেস্তোঁরা মাল্টিথ্রেড ব্যবহার করে। একটি থ্রেড আপনাকে অর্ডার করে এবং এটি প্রস্তুত করতে অন্য থ্রেড ব্যবহার করে এবং পরবর্তী গ্রাহকের সাথে অবিরত থাকে। সিঙ্ক্রোনাইজেশন পয়েন্ট কেবল তখনই কাজ করে যখন তারা কী কী প্রস্তুত করতে হয় তা তথ্যের আদান প্রদান করে। এর মতো একটি মডেল অনুসরণ করা সত্যিই জীবনকে সহজ করে তোলে।
অস্কারলাইজ

5
"পুরো ক্লাসের" হয় না লক করা আছে। জাভা মেশিন ভাষা স্পেসিফিকেশন : For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.তাই যদি একটি থ্রেড একটি স্ট্যাটিক পদ্ধতি প্রবেশ করে, একই বস্তু দ্বারা ফিরে অবজেক্ট # getClass লক করা আছে। অন্যান্য থ্রেড এখনও উদাহরণ পদ্ধতি অ্যাক্সেস করতে পারে।
মার্টিন অ্যান্ডারসন

4
হ্যাঁ আমি দেখতে পাচ্ছি যে আমার নিজের শব্দবন্ধটি চূড়ান্তভাবে কোনওটিই সঠিক নয়। আমি বলেছিলাম "এইভাবে যদি কোনও থ্রেড স্থিতিশীল পদ্ধতিতে প্রবেশ করে তবে অবজেক্ট # getClass দ্বারা লক করা একই বস্তুটি লক হয়ে গেছে"। প্রযুক্তিগতভাবে সঠিক নয়। সমস্ত কৌতূহলী লোকেদের জন্য দীর্ঘ গল্পটি সংক্ষিপ্ত করে তুলেছে: আপনার অ্যাপ্লিকেশনের প্রতিটি শ্রেণির জন্য একটি Classভার্চুয়াল মেশিনের ক্লাস লোডার দ্বারা ইনস্ট্যান্ট করা একটি অবজেক্ট রয়েছে । সমস্ত বস্তুর মতো, এই বস্তুরও Monitorএটির সাথে যুক্ত রয়েছে। এবং এই মনিটরটি লক করা হচ্ছে।
মার্টিন অ্যান্ডারসন

233

প্রশ্নটি আরও সাধারণভাবে সমাধান করার জন্য ...

মনে রাখবেন যে পদ্ধতিগুলিতে সিঙ্ক্রোনাইজ করা ব্যবহার করা আসলেই কেবল শর্টহ্যান্ড (ধরুন শ্রেণি সামারক্লাস):

synchronized static void foo() {
    ...
}

হিসাবে একই

static void foo() {
    synchronized(SomeClass.class) {
        ...
    }
}

এবং

synchronized void foo() {
    ...
}

হিসাবে একই

void foo() {
    synchronized(this) {
        ...
    }
}

আপনি যেকোন বস্তুকে লক হিসাবে ব্যবহার করতে পারেন। আপনি যদি স্থির পদ্ধতির সাবসেটগুলি লক করতে চান তবে আপনি এটি করতে পারেন

class SomeClass {
    private static final Object LOCK_1 = new Object() {};
    private static final Object LOCK_2 = new Object() {};
    static void foo() {
        synchronized(LOCK_1) {...}
    }
    static void fee() {
        synchronized(LOCK_1) {...}
    }
    static void fie() {
        synchronized(LOCK_2) {...}
    }
    static void fo() {
        synchronized(LOCK_2) {...}
    }
}

(অ স্থির পদ্ধতিগুলির জন্য, আপনি লকগুলি অ-স্থির ক্ষেত্র হিসাবে তৈরি করতে চান)


9
শীর্ষস্থানীয় 4 কোড ব্লকগুলি সোনার। ঠিক আমি খুঁজছেন ছিল কি. ধন্যবাদ.
রায়ান শিলিংটন

এটি কি সঠিক যে আমি অ স্থির পদ্ধতিতে একটি স্ট্যাটিক লক ব্যবহার করি, সামারক্লাস শ্রেণির কোনও দুটি অবজেক্ট একই সময়ে ব্লকটি চালাতে সক্ষম হবে না?
স্যামুয়েল

2
@ সামুয়েল - প্রায় ... এটি বস্তুর উদাহরণগুলির চেয়ে থ্রেড সম্পর্কে বেশি। আপনি ঠিক বলেছেন যে সামারক্লাসের পৃথক দৃষ্টান্তগুলি সকলেই একই লক / মনিটর ব্যবহার করবে: সোমারক্লাস.ক্লাস বস্তুর সাথে সম্পর্কিত। সুতরাং যদি দুটি ভিন্ন থ্রেড সোমারক্লাসের দুটি পৃথক দৃষ্টান্ত প্রক্রিয়া করছিল তবে তারা উভয় একই সময়ে চলতে পারে না। তবে, যদি একক থ্রেডটি সামারক্লাসের এক উদাহরণে কোনও পদ্ধতিকে ডেকে তোলে এবং অন্য পদ্ধতিতে সেই পদ্ধতিটিকে কোনও পদ্ধতি বলা হয়, তবে কোনও ব্লকিং ঘটবে না।
স্কট স্ট্যাঞ্চফিল্ড

@ স্কটস্ট্যানচফিল্ড সিঙ্ক্রোনাইজ করার পদ্ধতিগুলির জন্য আপনি তালিকা তালিকাবদ্ধ করেছেন, সেগুলি কি সব সমতুল্য?
Bionix1441

1
@ বায়োনিক্স ১৪৪৪ - এগুলি সমস্তই স্কোপিংয়ের। উপরের প্রতিটি প্রক্রিয়া আপনাকে লকিংয়ের আরও ভাল নিয়ন্ত্রণ দেয়। প্রথমে উদাহরণটি নিজেই একটি সম্পূর্ণ পদ্ধতি লক করে, তারপরে কোনও পদ্ধতিতে বিভাগগুলি লক করার জন্য নিজেই উদাহরণটি ব্যবহার করে, তারপরে বিভাগগুলি লক করার জন্য কোনও বস্তুর উদাহরণ।
স্কট স্টানচিল্ড

17

স্থিতিশীল পদ্ধতিগুলি ক্লাসটিকে লক করার জন্য অবজেক্ট হিসাবে ব্যবহার করে, এটি আপনার উদাহরণের জন্য ইউটিলস.ক্লাস। হ্যাঁ, এটা ঠিক আছে।


14

static synchronizedক্লাসের Classঅবজেক্টটিতে synchronizedতালা দেওয়া মানে যেখানে শ্রেণীর অবজেক্টটিতে নিজেই তালা দেওয়া হয়। এর অর্থ, আপনি যদি কোনও থ্রেডে (নির্বাহের) স্থিতিশীল সিঙ্ক্রোনাইজড পদ্ধতিতে অ্যাক্সেস করতে থাকেন তবে আপনি এখনও অন্য থ্রেড ব্যবহার করে স্থিতিক সিঙ্ক্রোনাইজড পদ্ধতিতে অ্যাক্সেস করতে পারবেন।

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


10

আপনি কেন প্রয়োগ করতে চান যে কেবলমাত্র একটি মাত্র থ্রেড যে কোনও সময় ডিবিতে অ্যাক্সেস করতে পারে?

এটি প্রয়োজনীয় যে কোনও লকিং বাস্তবায়ন ডাটাবেস ড্রাইভারের কাজ, এটি ধরে নেওয়া যে Connectionএটি একবারে কেবল একটি থ্রেড দ্বারা ব্যবহৃত হয়!

সম্ভবত, আপনার ডাটাবেস একাধিক, সমান্তরাল অ্যাক্সেস পরিচালনা করতে পুরোপুরি সক্ষম


আমি বাজি দিচ্ছি যে এটি কোনও ট্রানজেকশনাল সমস্যার জন্য কার্যকর নয়। অর্থাত্, সমাধানটি আসল সমস্যাটি সমাধান করে না
ম্যাট বি

1
আমি জানতাম না .... আমি ভেবেছিলাম আমাকে নিজে এটি প্রয়োগ করতে হবে। এটা ইশারা জন্য ধন্যবাদ! :)
টমেটো

2

যদি এটি আপনার ডাটাবেসে ডেটা দিয়ে কিছু করার থাকে তবে কেন ডাটাবেস আইসোলেশন লকিংটি ব্যবহারের জন্য ব্যবহার করবেন না?


আমার কোনও ডাটাবেস পটভূমি নেই। এখন আমি জানি!! এটা ইশারা জন্য ধন্যবাদ! :)
টমেটো

2

আপনার প্রশ্নের উত্তর দিতে, হ্যাঁ এটি করে: আপনার synchronizedপদ্ধতিটি একবারে একাধিক থ্রেড দ্বারা সম্পাদন করা যায় না।


2

synchronizedজাভা কীওয়ার্ড কীভাবে কাজ করে

আপনি যখন synchronizedএকটি স্ট্যাটিক পদ্ধতিতে কীওয়ার্ডটি যুক্ত করেন , তখন পদ্ধতিটি কেবল একবারে একটি থ্রেড দ্বারা কল করা যেতে পারে।

আপনার ক্ষেত্রে, প্রতিটি পদ্ধতির কল এই করবে:

  • নতুন একটি তৈরি কর SessionFactory
  • নতুন একটি তৈরি কর Session
  • সত্তা আনুন
  • সত্তাকে কলারে ফিরিয়ে দিন

তবে এগুলি আপনার প্রয়োজনীয়তা ছিল:

  • একই ডিবি উদাহরণটিতে তথ্য অ্যাক্সেস রোধ করতে আমি এটি চাই।
  • getObjectByIdযখন কোনও নির্দিষ্ট শ্রেণীর দ্বারা ডাকা হয় তখন সমস্ত ক্লাসের জন্য ডেকে আটকানো

সুতরাং, getObjectByIdপদ্ধতিটি থ্রেড-নিরাপদ হলেও বাস্তবায়নটি ভুল।

SessionFactory সেরা অনুশীলন

SessionFactoryথ্রেড-নিরাপদ, এবং এটা যেমন সত্তা শ্রেণীর পার্স এবং অভ্যন্তরীণ সত্তা metamodel উপস্থাপনা গড়ে তুলতে প্রয়োজন তৈরি করতে একটি খুব ব্যয়বহুল বস্তু আছে।

সুতরাং, আপনার SessionFactoryপ্রতিটি getObjectByIdপদ্ধতি কল চালু করা উচিত নয় ।

পরিবর্তে, আপনার এটির জন্য একটি সিঙ্গলটন উদাহরণ তৈরি করা উচিত।

private static final SessionFactory sessionFactory = new Configuration()
    .configure()
    .buildSessionFactory();

Sessionসবসময় বন্ধ করে দেওয়া উচিত

আপনি Sessionকোনও finallyব্লকটি বন্ধ করেননি এবং সত্তা লোড করার সময় যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয় তবে এটি ডাটাবেস সংস্থানগুলি ফাঁস করতে পারে।

Session.loadপদ্ধতি অনুসারে জাভাডক একটি নিক্ষেপ HibernateExceptionকরতে পারে যদি সত্তাটি ডাটাবেসে পাওয়া যায় না।

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

এজন্য আপনাকে এটিকে finallyবন্ধ করার জন্য একটি ব্লক ব্যবহার করতে হবে Session:

public static synchronized Object getObjectById (Class objclass, Long id) {    
     Session session = null;
     try {
         session = sessionFactory.openSession();
         return session.load(objclass, id);
     } finally {
         if(session != null) {
             session.close(); 
         }
     }
 }

বহু-থ্রেড অ্যাক্সেস প্রতিরোধ করা

আপনার ক্ষেত্রে, আপনি নিশ্চিত করতে চেয়েছিলেন যে কেবল একটি থ্রেড সেই নির্দিষ্ট সত্তায় অ্যাক্সেস পেয়েছে।

তবে synchronizedকীওয়ার্ডটি কেবল দুটি থ্রেডকে getObjectByIdএকই সাথে কল করতে বাধা দেয় । দুটি থ্রেড যদি একের পর এক এই পদ্ধতিটিকে কল করে তবে আপনার এই সত্তাটি ব্যবহার করে এখনও দুটি থ্রেড থাকবে।

সুতরাং, আপনি যদি কোনও প্রদত্ত ডাটাবেস অবজেক্টটি লক করতে চান যাতে অন্য কোনও থ্রেড এটি পরিবর্তন করতে না পারে, তবে আপনাকে ডাটাবেস লকগুলি ব্যবহার করতে হবে।

synchronizedমূলশব্দটি কেবল একটি একক জেভিএম-এ কাজ করে। আপনার যদি একাধিক ওয়েব নোড থাকে তবে এটি একাধিক জেভিএম জুড়ে মাল্টি-থ্রেড অ্যাক্সেসকে আটকাবে না।

আপনি কি করতে প্রয়োজন ব্যবহার LockModeType.PESSIMISTIC_READবাLockModeType.PESSIMISTIC_WRITE যখন ডিবি পরিবর্তন, ভালো প্রয়োগের:

Session session = null;
EntityTransaction tx = null;

try {
    session = sessionFactory.openSession();

    tx = session.getTransaction();
    tx.begin();

    Post post = session.find(
        Post.class, 
        id, 
        LockModeType.LockModeType.PESSIMISTIC_READ
    );

    post.setTitle("High-Performance Java Perisstence");

    tx.commit();
} catch(Exception e) {
    LOGGER.error("Post entity could not be changed", e);
    if(tx != null) {
        tx.rollback(); 
    }
} finally {
    if(session != null) {
        session.close(); 
    }
}

সুতরাং, আমি এটিই করেছি:

  • আমি একটি নতুন তৈরি করেছি EntityTransactionএবং একটি নতুন ডাটাবেস লেনদেন শুরু করেছি
  • Postসম্পর্কিত ডাটাবেস রেকর্ডটিতে একটি লক ধরে রাখার সময় আমি সত্তাটি লোড করেছি
  • আমি Postসত্তাটি পরিবর্তন করেছি এবং লেনদেনের প্রতিশ্রুতিবদ্ধ
  • Exceptionনিক্ষিপ্ত হওয়ার ক্ষেত্রে , আমি লেনদেনটি ফিরিয়ে আনি

এসিডি এবং ডাটাবেস লেনদেন সম্পর্কে আরও তথ্যের জন্য, এই নিবন্ধটিও পরীক্ষা করে দেখুন ।

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