質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

1470閲覧

java メッセージキューの処理 mainとは別のスレッドでA,Bを動かす

a.ix.

総合スコア1

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2021/11/20 16:04

前提・実現したいこと

クラスをAsanからBsanへキューを使ってメッセージを送る。
クラスをAsan,Bsanでくりかえしメッセージを送れるようにする。
Aさん,Bさんオブジェクトが,プロキシオブジェクトを介して通信するプログラムを作る。
実現するシーケンスは添付した画像の通りです。
イメージ説明

これに
「proxyもAsan,Bsan同様にmainとは別のスレッドで動かす。」
という内容を追加したいのですがいまくいかないので質問させてもらいました。

■■な機能を実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

java

1ソースコード

class Queue {
private String[] buf;
private int messagein = 0;
int start = 0;

public Queue(int size) { // 指定されたサイズでバッファを確保 buf = new String[size]; } public synchronized void writeMessage(String str) throws InterruptedException { // すでにメッセージがある場合 while (messagein >= buf.length) { // notifyされるまで待機 wait(); } int end = (start + messagein) % buf.length; buf[end] = str; // メッセージが入った messagein++; notifyAll(); } public synchronized String readMessage() throws InterruptedException { // メッセージが入るまで待つ while (messagein == 0) { // notifyされるまで待機 wait(); } String message = buf[start]; start = (start + 1) % buf.length; // メッセージがなくなった messagein--; notifyAll(); return message; }

}

class Proxy {
Queue[] queue = new Queue[3];

public Proxy() { queue[0] = new Queue(10); queue[1] = new Queue(10); queue[2] = new Queue(10); } public void send(String source, String message) { try { if (source.equals("Aさん")) { queue[1].writeMessage(message); queue[0].writeMessage("100 Trying"); } else { queue[0].writeMessage(message); } } catch (Exception e) { System.err.println(e.getMessage()); } } public String recv(String source) { String ret = new String(); try { if (source.equals("Aさん")) { ret = queue[0].readMessage(); } else { ret = queue[1].readMessage(); } } catch (Exception e) { System.err.println(e); } return ret; }

}

class Asan implements Runnable {
Proxy proxy;
String name = "Aさん";

Asan(Proxy proxy) { this.proxy = proxy; } public void run() { try { String message = "INVITE"; System.out.println(name + " send: " + message); proxy.send(name, message); Thread.sleep(1000); System.out.println(name + " recv: " + proxy.recv(name)); Thread.sleep(1000); System.out.println(name + " recv: " + proxy.recv(name)); Thread.sleep(5000); System.out.println(name + " recv: " + proxy.recv(name)); } catch (Exception e) { System.err.println(e.getMessage()); } }

}

class Bsan implements Runnable {
Proxy proxy;
String name = "Bさん";

Bsan(Proxy proxy) { this.proxy = proxy; } public void run() { try { Thread.sleep(1000); System.out.println(name + " recv: " + proxy.recv(name)); Thread.sleep(1000); String message = "180 Ringing"; System.out.println(name + " send: " + message); proxy.send(name, message); Thread.sleep(3000); message = "200 OK"; System.out.println(name + " send: " + message); proxy.send(name, message); } catch (Exception e) { System.err.println(e.getMessage()); } }

}

public class Main {
public static void main(String args[]) {
Proxy proxy = new Proxy();

Asan sy1 = new Asan(proxy); Bsan sy2 = new Bsan(proxy); Thread th1 = new Thread(sy1); Thread th2 = new Thread(sy2); th1.start(); th2.start(); }

}

試したこと

できた内容はソースコードのところまでです。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2021/11/20 17:00

コードはファイル毎にマークダウン記法でご提示ください。 マークダウンにつきましてはヘルプをご参照ください。
jimbe

2021/11/20 17:06

> ~ いまくいかないので ~ 何が「うまく」いかないのでしょうか。ただ出来ませんでは丸投げになります。 どの部分でどの様な意図のコードがどうなってしまうのでしょうか。また、それに対してどの様な調査・対処を試みられて、どのような結果になったのでしょうか。 それらを「試したこと」に追記して頂きたく思います。
guest

回答1

0

ベストアンサー

Proxy に受信用 Queue を作り、Proxy.send() はそのキューに追加、Proxyスレッドはそのキューで受信待ちをしていて、受信次第各送信先のキューに送信・・・でしょうか。

以下は、メッセージを"それっぽく"クラス化、Queueをジェネリクス化して送信先毎に Map 管理、Proxyスレッドの停止にもメッセージを使うようにする等しています。

java

1package teratail_java.q370289; 2 3import java.time.LocalDateTime; 4import java.time.format.DateTimeFormatter; 5import java.util.HashMap; 6import java.util.Map; 7 8class Queue<T> { 9 private Object[] buf; 10 private int messagein = 0; 11 int start = 0; 12 13 public Queue(int size) { 14 // 指定されたサイズでバッファを確保 15 buf = new Object[size]; 16 } 17 public Queue() { 18 this(10); 19 } 20 21 public synchronized void writeMessage(T message) throws InterruptedException { 22 // すでにメッセージがある場合 23 while (messagein >= buf.length) { 24 // notifyされるまで待機 25 wait(); 26 } 27 int end = (start + messagein) % buf.length; 28 buf[end] = message; 29 // メッセージが入った 30 messagein++; 31 notifyAll(); 32 } 33 34 public synchronized T readMessage() throws InterruptedException { 35 // メッセージが入るまで待つ 36 while (messagein == 0) { 37 // notifyされるまで待機 38 wait(); 39 } 40 41 @SuppressWarnings("unchecked") 42 T message = (T)buf[start]; 43 44 start = (start + 1) % buf.length; 45 // メッセージがなくなった 46 messagein--; 47 notifyAll(); 48 return message; 49 } 50} 51 52class Message { 53 static final int CODE_INVITE = 0; 54 static final int CODE_UNREGISTER = -999; 55 56 final String src; 57 final String dst; 58 final int code; 59 final String text; 60 Message(String src, String dst, int code) { 61 this(src, dst, code, ""); 62 } 63 Message(String src, String dst, int code, String text) { 64 this.src = src; 65 this.dst = dst; 66 this.code = code; 67 this.text = text; 68 } 69 public String getTextWithCode() { 70 return (code<=0?"":code+" ")+text; 71 } 72 @Override 73 public String toString() { 74 return "src='"+src+"', dst='"+dst+"', code="+code+", text='"+text+"'"; 75 } 76} 77 78class Proxy implements Runnable { 79 static final String name = "Proxy"; 80 81 private Queue<Message> accept = new Queue<Message>(); 82 private Map<String,Queue<Message>> map = new HashMap<>(); //名前とキューの対応 83 84 public void run() { 85 try { 86 while(true) { 87 Message msg = accept.readMessage(); 88 if(msg.dst.equals(name)) { 89 if(msg.code == Message.CODE_UNREGISTER) { 90 map.remove(msg.src); 91 if(map.isEmpty()) break; //利用者が居なくなったら終了 92 } 93 } else { 94 getQueue(msg.dst).writeMessage(msg); 95 if(msg.code == Message.CODE_INVITE) { 96 getQueue(msg.src).writeMessage(new Message(name, msg.src, 100, "Trying")); 97 } 98 } 99 } 100 } catch (InterruptedException e) { 101 e.printStackTrace(System.err); 102 } 103 } 104 105 private Queue<Message> getQueue(String name) { 106 synchronized(map) { 107 Queue<Message> q = map.get(name); 108 if(q == null) { 109 q = new Queue<Message>(); 110 map.put(name, q); 111 } 112 return q; 113 } 114 } 115 116 public void send(Message msg) throws InterruptedException { 117 if(!msg.src.equals(name) && !msg.dst.equals(name)) { //Proxy[から|へ]は表示しない 118 printLog(msg.src + " send: " + msg.getTextWithCode()); 119 } 120 accept.writeMessage(msg); 121 } 122 123 public Message recv(String name) throws InterruptedException { 124 Message msg = getQueue(name).readMessage(); 125 printLog(name + " recv: " + msg.getTextWithCode()); 126 return msg; 127 } 128 129 private void printLog(String log) { 130 String time = DateTimeFormatter.ofPattern("HH:mm:ss ").format(LocalDateTime.now()); 131 System.out.println(time + log); 132 } 133} 134 135class Asan implements Runnable { 136 static final String name = "Aさん"; 137 138 private Proxy proxy; 139 140 Asan(Proxy proxy) { 141 this.proxy = proxy; 142 } 143 144 public void run() { 145 try { 146 proxy.send(new Message(name, Bsan.name, Message.CODE_INVITE, "INVITE")); 147 Thread.sleep(1000); 148 proxy.recv(name); //Trying? 149 Thread.sleep(1000); 150 proxy.recv(name); //Ringing? 151 Thread.sleep(5000); 152 proxy.recv(name); //OK? 153 154 proxy.send(new Message(name, Proxy.name, Message.CODE_UNREGISTER)); 155 } catch (Exception e) { 156 e.printStackTrace(System.err); 157 } 158 } 159} 160 161class Bsan implements Runnable { 162 static final String name = "Bさん"; 163 164 private Proxy proxy; 165 166 Bsan(Proxy proxy) { 167 this.proxy = proxy; 168 } 169 170 public void run() { 171 try { 172 Thread.sleep(1000); 173 Message recvMsg = proxy.recv(name); //INVITE? 174 Thread.sleep(1000); 175 proxy.send(new Message(name, recvMsg.src, 180, "Ringing")); 176 Thread.sleep(3000); 177 proxy.send(new Message(name, recvMsg.src, 200, "OK")); 178 179 proxy.send(new Message(name, Proxy.name, Message.CODE_UNREGISTER)); 180 } catch (Exception e) { 181 e.printStackTrace(System.err); 182 } 183 } 184} 185 186public class Main { 187 public static void main(String args[]) throws InterruptedException { 188 Proxy proxy = new Proxy(); 189 Asan sy1 = new Asan(proxy); 190 Bsan sy2 = new Bsan(proxy); 191 192 Thread threads[] = { new Thread(proxy), new Thread(sy1), new Thread(sy2) }; 193 194 for(Thread th : threads) th.start(); 195 for(Thread th : threads) th.join(); 196 } 197}

実行結果

plain

114:11:47 Aさん send: INVITE 214:11:48 Bさん recv: INVITE 314:11:48 Aさん recv: 100 Trying 414:11:49 Bさん send: 180 Ringing 514:11:49 Aさん recv: 180 Ringing 614:11:52 Bさん send: 200 OK 714:11:54 Aさん recv: 200 OK

投稿2021/11/20 20:08

編集2021/11/21 05:13
jimbe

総合スコア13209

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問