5
回答
关于synchronized 的问题
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

最近对发送mail部分的程序进行改造,原来好好的,修改后发现web服务起来之后只能发送一封,就发布出去了。

只是改造了一下同步块,是在想不明白,大家帮忙看看吧~

原来好用的程序:

public class MailSendHandler implements Runnable {

	private static MailSendHandler me = null;
	/**
       * Log4j Logger对象创建
       */
	private static Logger logger = null;

	/**
	 *  关闭默认构造函数
	 */
	private MailSendHandler() {
	}

	/**
	 * 唯一实例化接口
	 * @return
	 */
	public static MailSendHandler getInstance() {
		if (null == me) {
			synchronized (MailSendHandler.class) {
				if (null == me) {
		                    me = new MailSendHandler();
		                    if (logger == null) {
		                        logger = Logger.getLogger(MailSendHandler.class);
		                    }
				}
			}
		}
		return me;
	}

	/**
	 * 全局静态变量
	 */
	/** 待发送邮件队列*/
	private static LinkedQueue<QueueValue> linkedQueue;
	/** 线程是否在进行中*/
	private static boolean isRun = false;
	/**
	 * 邮件发送主程序
	 * @param args
	 */
	private static void main(String[] args) {

		boolean bForever = true;
		QueueValue queueValue = null;
		Mail email = null;
		MailSender mailSender = null;
		try {
			while (bForever) {
				// 如果队列中没有对象了,则不再执行
				if(linkedQueue.isEmpty()){
					break;
				} else {
					queueValue = linkedQueue.get();
					email = queueValue.getMail();
					mailSender  = queueValue.getMailSender();
					mailSender.send(email);
				}
			}
		} catch (Exception e) {
		    logger.error(e);
		} finally {
			isRun = false;
		}
	}

	/**
	 * 线程启动接口
	 */
	public void run() {
		MailSendHandler.main(null);
	}


	/**
	 * 用户接口,发送邮件的监听器
	 * @param mailSenderP
	 * @param email
	 */
	public void listen(QueueValue queueValue) {
		if (linkedQueue == null) {
			synchronized (LinkedQueue.class) {
				if (null == linkedQueue) {
					linkedQueue = new LinkedQueue<QueueValue>();	
				}
			}
		}
		
		linkedQueue.put(queueValue);
		
		// 如果线程正在运行中则不在另起线程。
		if (!isRun) {
			Thread t = new Thread(me);
			t.start();
			isRun = true;
		}
	}
}

修改后,不好用的source:

public class MailSendHandler implements Runnable {

	private static MailSendHandler me = null;
	/**
       * Log4j Logger对象创建
       */
      private static Logger logger = null;

	/**
	 *  关闭默认构造函数
	 */
	private MailSendHandler() {
	}

	/**
	 * 唯一实例化接口
	 * @return
	 */
	public static MailSendHandler getInstance() {
		if (null == me) {
			synchronized (MailSendHandler.class) {
				if (null == me) {
		                    me = new MailSendHandler();
		                    if (logger == null) {
		                        logger = Logger.getLogger(MailSendHandler.class);
		                    }
				}
			}
		}
		return me;
	}

	/**
	 * 全局静态变量
	 */
	/** 待发送邮件队列*/
	private static LinkedQueue<QueueValue> linkedQueue;
	/** 线程是否在进行中*/
	private static boolean isRun = false;
	/**
	 * 邮件发送主程序
	 * @param args
	 */
	private static void main(String[] args) {

		boolean bForever = true;
		QueueValue queueValue = null;
		Mail email = null;
		MailSender mailSender = null;
		try {
			while (bForever) {
				synchronized (LinkedQueue.class) {
					// 如果队列中没有对象了,则不再执行
					if(linkedQueue.isEmpty()){
						break;
					} else {
						queueValue = linkedQueue.get();
						email = queueValue.getMail();
						mailSender  = queueValue.getMailSender();
						mailSender.send(email);
					}
				}
			}
		} catch (Exception e) {
			 logger.error(e);
		} finally {
			isRun = false;
		}
	}

	/**
	 * 线程启动接口
	 */
	public void run() {
		MailSendHandler.main(null);
	}


	/**
	 * 用户接口,发送邮件的监听器
	 * @param mailSenderP
	 * @param email
	 */
	public void listen(QueueValue queueValue) {
		
		if (linkedQueue == null) {
			synchronized (LinkedQueue.class) {
				if (null == linkedQueue) {
					linkedQueue = new LinkedQueue<QueueValue>();	
				}
		        linkedQueue.put(queueValue);
			}
		}
		
		// 如果线程正在运行中则不在另起线程。
		if (!isRun) {
			Thread t = new Thread(me);
			t.start();
			isRun = true;
		}
	}
}

主要修改部分就是在操作队列的时候加入同步线程锁而已,为什么会导致只能一次好用呢?

PS:修改点在main方法和listen方法。

真是奇怪~

举报
jing31
发帖于7年前 5回/319阅
共有5个答案 最后回答: 7年前

你listen 改完后,只有在

 

  1.   if (linkedQueue == null) {  
  2.             synchronized (LinkedQueue.class) {  
  3.                 if (null == linkedQueue) {  
  4.                     linkedQueue = new LinkedQueue<QueueValue>();    
  5.                 }  
  6.                 linkedQueue.put(queueValue);  
  7.             }  
  8.         }  

linkedQueue被第一次实例化的时候才调用put操作.... 你的queue里应该只有一个值吧

这个确实是程序bug,修改如下:

        if (linkedQueue == null) {
            synchronized (LinkedQueue.class) {
                if (null == linkedQueue) {
                    linkedQueue = new LinkedQueue<QueueValue>();
                }
            }
        }
        
        linkedQueue.put(queueValue);
        
        // 如果线程正在运行中则不在另起线程。
        if (!isRun) {
            Thread t = new Thread(me);
            t.start();
            isRun = true;
        }

如果这部分修改后,整体的synchronized 操作是不是就没有问题了呢?

或者说,这样设计是否合理呢?

 你只不过是希望得到一个在多线程环境下的单例而已 可以看看单例模式的多线程环境下的实现吧  我对这个也是不甚了解的~

看不出改了哪里-_-||

建议看一下包java.util.concurrent里的class,用这些api处理同步。以前写过一个多线程的爬虫就是用里面的class,好用

引用来自#5楼“烈冰”的帖子

看不出改了哪里-_-||

建议看一下包java.util.concurrent里的class,用这些api处理同步。以前写过一个多线程的爬虫就是用里面的class,好用

只是加了synchronized 块处理而已~

顶部