Sobes.tech
Middle

Kā organizēt datu apmaiņu starp diviem pavedieniem Java?

sobes.tech AI

Atbilde no AI

Datu apmaiņa starp straumēm Java var tikt organizēta šādi:

  • Kopīgas mainīgās ar sinhronizāciju: Strauji izmanto kopīgas mainīgās, kuru piekļuve tiek sinhronizēta ar synchronized atslēgas vārdu, bloķēšanas (Lock no java.util.concurrent.locks) vai atomu mainīgajiem (Atomic no java.util.concurrent.atomic).
  • Datu konvejeri (Piped Streams): Saistītie ievades/izvades straumes (PipedInputStream un PipedOutputStream) ļauj vienam straumēm rakstīt datus, bet otrai - tos lasīt:
    // Piped Streams izmantošana
    mēģiniet {
        PipedOutputStream pout = jauns PipedOutputStream();
        PipedInputStream pin = jauns PipedInputStream(pout);
    
        // Strāva 1: rakstīšana
        jauns Tēma (()-> {
            mēģiniet {
                pout.write("Sveiki no straumes 1".getBytes());
                pout.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    
        // Strāva 2: lasīšana
        jauns Tēma (()-> {
            mēģiniet {
                int dati;
                kamēr ((dati = pin.read()) != -1) {
                    System.out.print((char) dati);
                }
                pin.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    } catch (Exception e) {
        e.printStackTrace();
    }
    
  • Rindas (Queues): Izmantojot drošas straumes kolekcijas, piemēram, BlockingQueue (piemēram, ArrayBlockingQueue, LinkedBlockingQueue), ļauj vienam straumēm pievienot elementus rindā, bet otram - tos izņemt:
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    // Izmantojot BlockingQueue
    BlockingQueue<String> rinda = jauna LinkedBlockingQueue<>();
    
    // Ražotājs
    jauns Tēma (()-> {
        mēģiniet {
            rinda.put("Ziņa 1");
            rinda.put("Ziņa 2");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    
    // Patērētājs
    jauns Tēma (()-> {
        mēģiniet {
            System.out.println(rinda.take());
            System.out.println(rinda.take());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    
  • wait(), notify(), notifyAll(): Izmanto objektu monitoriem balstītu saskaņošanu starp straumēm. Viena straume izsauc wait(), lai gaidītu nosacījumu, otra - notify() vai notifyAll(), lai paziņotu gaidošajām straumēm par nosacījuma izmaiņām:
    // wait/notify izmantošana
    klase `Data` {
        privāts String message;
        privāts boolean empty = patiesība;
    
        publiska sinhronizēta String lasīt() {
            kamēr (empty) {
                mēģiniet {
                    wait(); // gaidām datus
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            empty = patiesība;
            notifyAll(); // paziņojam par rakstīšanas iespēju
            atgriezt message;
        }
    
        publiska sinhronizēta void rakstīt(String message) {
            kamēr (!empty) {
                mēģiniet {
                    wait(); // gaidām, kamēr iepriekšējie dati tiks izlasīti
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            empty = patiesība;
            this.message = message;
            notifyAll(); // paziņojam par jauniem datiem
        }
    }
    
  • CompletableFuture: ļauj izveidot asenhroniskas aprēķinus un apvienot to rezultātus, nodrošinot datu apmaiņu caur atgrieztajām vērtībām un pabeigšanas apstrādātājiem.
  • Exchanger: ļauj diviem straumēm apmainīties ar objektiem sinhronizācijas punktā.

Konkrēta metodes izvēle ir atkarīga no uzdevuma specifikas, nepieciešamā sinhronizācijas līmeņa, veiktspējas un realizācijas sarežģītības.