【问题标题】:Java Synchronized method...not synchronizedJava同步方法...不同步
【发布时间】:2012-11-13 15:49:43
【问题描述】:

对于我当前的 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();
        }
    }
}
}

【问题讨论】:

  • 最好是发布你的代码而不是描述它。
  • System.out.println("*****************************************************************************"); 星号是不是打印太多了?

标签: java synchronized


【解决方案1】:

你应该在两个线程都可以访问的对象上同步你的方法,因为现在你正在使用你所在的对象实例来同步哪个原因永远不会产生影响,因为两个线程只停留在它们的范围内据我了解你的问题。您可以在创建时将一个简单的对象传递给两个线程,然后像这样重新格式化您的方法

传递对象进行同步:

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
   }
}

【讨论】:

    【解决方案2】:

    当您将 readMail() 作为方法同步时,一次只有一个线程可以访问 Objects readMail() 方法。如果您有两个具有 readMail() 方法的 GMail 类型的不同对象实例,则两个线程可以不同步(并行)访问它们。

    换句话说,阻止 readMail() 方法执行的信号量实际上是 GMail 对象。对于两个不同的对象实例,您有两个不交互的信号量。

    如果您只有一个具有同步 readMail() 方法的 GMail 对象实例,它会起作用。然后一次只有一个线程可以访问它。

    【讨论】:

      【解决方案3】:

      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 的实例并将其传递给您的线程。

      【讨论】:

      • 线程调用的方法是readMail,恰好在gmail类中。除了这个,readMail 不会调用任何方法
      • 你能解释一下store参数吗?我不太明白
      • store 是您在现有 readMail 方法中使用的第一个变量。我只是允许您将该变量传递给辅助方法。您也可以改为传递文件夹,或者什么都不传递。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-10
      • 2014-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      相关资源
      最近更新 更多