Sobes.tech
Middle

როგორ შეიძლება ორგანიზება გაუკეთდეს მონაცემთა გაცვლას ორ ნაკადს შორის Java-ში?

sobes.tech AI

პასუხი AI-სგან

Java- ში ნაკადებს შორის მონაცემთა გაცვლა ორგანიზებული შეიძლება შემდეგი მეთოდებით:

  • საერთო ცვლადები სინქრონიზაციით: ნაკადები იყენებენ საერთო ცვლადებს, რომელთა წვდომა სინქრონიზირებულია synchronized საკვანძო სიტყვით, ბლოკებით (Lock java.util.concurrent.locks-დან) ან ატომური ცვლადებით (Atomic java.util.concurrent.atomic-დან):
  • მონაცემთა კონვეიერები (Piped Streams): დაკავშირებული შესვლის/გამოსვლის ნაკადები (PipedInputStream და PipedOutputStream) საშუალებას აძლევს ერთ ნაკადს წერდეს მონაცემებს, ხოლო მეორე - კითხულობს:
    // Piped Streams-ის გამოყენება
    სცადეთ {
        PipedOutputStream pout = ახალი PipedOutputStream();
        PipedInputStream pin = ახალი PipedInputStream(pout);
    
        // ნაკადი 1: წერა
        ახალი თემა (()-> {
            სცადეთ {
                pout.write("გამარჯობა ნაკადიდან 1".getBytes());
                pout.close();
            } დაჭერა (Exception e) {
                e.printStackTrace();
            }
        }).start();
    
        // ნაკადი 2: კითხვა
        ახალი თემა (()-> {
            სცადეთ {
                int data;
                სანამ ((data = pin.read()) != -1) {
                    System.out.print((char) data);
                }
                pin.close();
            } დაჭერა (Exception e) {
                e.printStackTrace();
            }
        }).start();
    } დაჭერა (Exception e) {
        e.printStackTrace();
    }
    
  • ნაკადები (Queues): გამოყენებით უსაფრთხო კოლექციებს, როგორიცაა BlockingQueue (მაგალითად, ArrayBlockingQueue, LinkedBlockingQueue), ერთ ნაკადს შეუძლია ელემენტების დამატება რიგში, ხოლო მეორე - ამოღება:
    იმპორტი java.util.concurrent.BlockingQueue;
    იმპორტი java.util.concurrent.LinkedBlockingQueue;
    
    // გამოყენება BlockingQueue
    BlockingQueue<String> queue = ახალი LinkedBlockingQueue<>();
    
    // მწარმოებელი
    ახალი თემა (()-> {
        სცადეთ {
            queue.put("შეტყობინება 1");
            queue.put("შეტყობინება 2");
        } დაჭერა (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    
    // მომხმარებელი
    ახალი თემა (()-> {
        სცადეთ {
            System.out.println(queue.take());
            System.out.println(queue.take());
        } დაჭერა (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    
  • wait(), notify(), notifyAll(): გამოიყენება ობიექტის მონიტორების საფუძველზე ნაკადების სინქრონიზაციისთვის. ერთი ნაკადი იძახის wait(), რათა დაელოდოს პირობას, მეორე - notify() ან notifyAll(), რათა აცნობოს მოლოდინში მყოფ ნაკადებს პირობების ცვლილების შესახებ:
    // wait/notify-ის გამოყენება
    კლასი `Data` {
        პირადი String message;
        პირადი boolean empty = ჭეშმარიტი;
    
        საჯარო სინქრონული String read() {
            სანამ (empty) {
                სცადეთ {
                    wait(); // მონაცემების მოლოდინში
                } დაჭერა (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            empty = ჭეშმარიტი;
            notifyAll(); // შეტყობინება წერის შესაძლებლობის შესახებ
            დაბრუნება message;
        }
    
        საჯარო სინქრონული void write(String message) {
            სანამ (!empty) {
                სცადეთ {
                    wait(); // მოლოდინში წინა მონაცემების წაკითხვა
                } დაჭერა (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            empty = ჭეშმარიტი;
            this.message = message;
            notifyAll(); // ახალი მონაცემების არსებობის შეტყობინება
        }
    }
    
  • CompletableFuture: საშუალებას აძლევს შექმნას ასინქრონული გამოთვლები და მათი შედეგების გაერთიანება, უზრუნველყოფს მონაცემთა გაცვლას დაბრუნებული მნიშვნელობებისა და დამთავრების დამუშავებლების საშუალებით.
  • Exchanger: საშუალებას აძლევს ორ ნაკადს გაცვალოს ობიექტები სინქრონიზაციის წერტილში.

შერჩევა კონკრეტული მეთოდის დამოკიდებულია ამოცანის სპეციფიკაზე, საჭირო სინქრონიზაციის დონეზე, შესრულების სიჩქარეზე და განხორციელების სირთულეზე.