2

現在の Java 演習では、2 つの異なる Gmail アカウントからメールを取得する必要があります。gmail クラスの新しいインスタンスを作成することでこれを行いました。gmail クラスはスレッドを拡張し、その中にメールを取得して印刷する同期メソッド readMail() があります。この readMail メソッドは run メソッドによって while(true) ループで呼び出され、その後 30 秒間スリープします。これは、30 秒ごとにメールを取得するという考え方です。ただし、同期方法は機能しないようです。スレッドは互いに割り込み、他のスレッドが割り込みをかけて印刷を開始する前に、メソッドはメッセージのすべての項目を印刷しません。

アドバイスをいただければ幸いです。

問題を引き起こしている以下の方法を参照してください。

public synchronized void readMail() throws MessagingException, IOException {
    Folder inbox = store.getFolder("Inbox");
    inbox.open(Folder.READ_ONLY);
    messages = inbox.getMessages();
    // System.out.println("No of Messages : " + inbox.getMessageCount());
    // System.out.println("No of Unread Messages : "
    // + inbox.getUnreadMessageCount());

    for (int i = 0; i < inbox.getUnreadMessageCount(); i++) {

        System.out
                .println("*****************************************************************************");
        System.out.println("NEW MESSAGE " + (i + 1) + ":");
        msg = messages[i];
        // System.out.println(msg.getMessageNumber());
        // Object String;
        // System.out.println(folder.getUID(msg)

        String subject = msg.getSubject();

        System.out.println("Subject: " + subject);
        System.out.println("From: " + msg.getFrom()[0]);
        System.out.println("To: " + msg.getAllRecipients()[0]);
        System.out.println("Date: " + msg.getReceivedDate());
        System.out.println("Size: " + msg.getSize());
        // System.out.println(msg.getFlags());
        // System.out.println("Body: \n"+ msg.getContent());
        // System.out.println(msg.getContentType());
    }
}

次に、実行方法:

    public void run() {
    while (true) {

        try {
            readMail();
        } catch (MessagingException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        try {
            sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
}
4

3 に答える 3

5

両方のスレッドがアクセスできるオブジェクトでメソッドを同期する必要があります。現在、現在のオブジェクトインスタンスを使用して同期を行っているため、どちらのスレッドも効果がないため、理解できる限り両方のスレッドがオンスコープ内にとどまるためです。あなたの質問。作成時に単純なオブジェクトを両方のスレッドに渡し、メソッドを次のように再フォーマットできます

同期するオブジェクトを渡します:

public static void main(String[] args){
     Object obj = new Object();
     gmail g1 = new gmail(obj);
     gmail g2 = new gemail(obj);
     // more code
}

gmail クラスに参照を保存:

public class gmail extends Thread{
    private Object sharedObject;

    public gmail( Object synchronizer){
          sharedObject = synchronzier;
    }

その上で同期します:

public void readMail(){
   synchronized( sharedObject ){
       // your method code goes here
   }
}

この例では、gmail のクラス オブジェクトでの同期も可能で、さらに簡単です

public void readMail(){
   synchronized( this.getClass() ){
       // your method code goes here
   }
}
于 2012-11-13T16:07:40.573 に答える
3

メソッドとして readMail() を同期すると、一度に 1 つのスレッドだけがオブジェクトのreadMail() メソッドにアクセスできます。readMail() メソッドを持つ GMail 型の 2 つの異なるオブジェクト インスタンスがある場合、2 つのスレッドが非同期で (並行して) それらにアクセスできます。

つまり、readMail() メソッドの実行をブロックするセマフォは、実際には GMail オブジェクトです。2 つの異なるオブジェクト インスタンスでは、相互作用しない 2 つのセマフォがあります。

同期された readMail() メソッドを持つ GMail オブジェクトのインスタンスが 1 つしかない場合に機能します。その後、一度に 1 つのスレッドしかアクセスできませんでした。

于 2012-11-13T16:07:52.370 に答える
2

synchronizedキーワードは、スレッド内のメソッドではなく、スレッドが呼び出すメソッドに適用されます。

したがって、readMailスレッドで定義されているメソッドは、すべてのスレッドが使用する、別の場所で定義されている他のメソッドを呼び出す必要があり、そのメソッドを同期します。

だからクラスを作る

public class MailHelper {
   public static void synchronized doRead(store) throws MessagingException, IOException {
       // all your readMail code here, except pass in the store
   }
}

そしてあなたのスレッドクラスで

public void readMail() throws MessagingException, IOException {
    // get your store
     MailHelper.doRead(store);
}

メソッドをMailHelper静的にできないことに注意してください。その場合、MailHelper のインスタンスを作成してスレッドに渡す必要があります。

于 2012-11-13T15:52:05.337 に答える