最近作注册的时候,发现同步发送注册邮件多了一个耗时,就想到异步处理邮件发送,直接返回成功给用户。api
设计了一个线程,用来发送邮件,须要发送的时候再来唤醒就行了,可是对于没有系统了解过多线程的我来讲,想的太简单了。多线程
public class MailSendThread extends Thread{ private static Logger log = Logger.getLogger(MailSendThread.class); public final static long mail_user_time = 48 * 1800000L;//一天运行一次 public void run(){ log.error("MailSendThread is running!"); try { MailUtil.sendMailInfo(); sleep(mail_user_time); } catch (Exception e) { // TODO Auto-generated catch block log.error("MailSendThread run error", e); } } }
private static MailSendThread mailSender = new MailSendThread(); public static void notifyMailSender(){ mailSender.notify(); }
多傻的代码!!!!异步
仔细研究后发现,首先sleep只能用做线程内部等待使用,指定时间段内休眠,不能外部唤醒;函数
其次,nofity方法必须依托与一个线程正在等待的对象,就是锁住的对象,不能直接对线程操做,由于wait函数须要一个锁;this
研究了一下生产者和消费者,这里用到的锁是对象实例spa
package com.thread; /** * 生产者,制造馒头 * @author huangjc * */ public class A extends Thread{ private C c; public A(C c){ this.c = c; } public void run(){ int i=0; while(i < 10){ try { c.add(); i++; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package com.thread; /** * 消费者,消耗馒头 * @author huangjc * */ public class B extends Thread{ private C c; public B(C c){ this.c = c; } public void run(){ int i=0; while(i<10){ i++; c.minus(); } } public static void main(String[] args) { C c = new C(); new Thread(new B(c)).start(); new Thread(new A(c)).start(); } }
具体的锁就在下面线程
package com.thread; public class C { private static int i=0; public synchronized void add() throws InterruptedException{ System.out.println("增长馒头:如今有"+(i)+"个馒头"); if(i == 5){ System.out.println("馒头够多了,赶快吃吧!"); wait(); }else{ i++; System.out.println("放了一个馒头"); notify();//唤醒消耗线程 } } public synchronized void minus(){ System.out.println("取出馒头:如今有"+(i)+"个馒头"); if (i == 0){ System.out.println("馒头没有了,等会儿吧!"); try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ i--; System.out.println("取出一个馒头"); notify(); } } }
这里的notify和wait方法锁住的都是在B的main方法中建立的实例对象设计
因此问题又来了,我须要在主线程中启动分线程,因此不能给两个线程分配同一个实例对象,若是每次都从新分配一个实例对象,再建立一个分线程,是否是太愚蠢了;code
对于静态方法和非静态方法的同步问题,静态方法锁住的是Class,例如A.class,而非静态方法锁住的是当前实例。对象
因此静态方法和非静态方法并不适用同一个锁。一个类中的全部静态方法使用同一个锁。
因此,是否能够考虑使用静态方法来发送邮件,锁住类自己,而后再主线程中依托类自己进行唤醒;
太坑爹了,彻底不是这回事,查了API后发现,wait方法是Object对象的,那不就是说必须依托于一个对象实例吗?
再来看api中关于thread类下面的方法,其中有个
interrupt()
interrupt public void interrupt() 中断线程。 若是当前线程没有中断它本身(这在任何状况下都是容许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException。 若是线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程当中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。 若是该线程在可中断的通道上的 I/O 操做中受阻,则该通道将被关闭,该线程的中断状态将被设置而且该线程将收到一个 ClosedByInterruptException。 若是该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将当即从选择操做返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法同样。 若是之前的条件都没有保存,则该线程的中断状态将被设置。 中断一个不处于活动状态的线程不须要任何做用。 抛出: SecurityException - 若是当前线程没法修改该线程
线程A正在使用sleep()暂停着: Thread.sleep(100000);
若是要取消他的等待状态,能够在正在执行的线程里(好比这里是B)调用
a.interrupt();
令线程A放弃睡眠操做,这里a是线程A对应到的Thread实例
执行interrupt()时,并不须要获取Thread实例的锁定.任何线程在任什么时候刻,均可以调用其余线程interrupt().当sleep中的线程被调用interrupt()时,就会放弃暂停的状态.并抛出InterruptedException.丢出异常的,是A线程
package com.thread; /** * 消费者,消耗馒头 * @author huangjc * */ public class B extends Thread{ public void run(){ while(true){ System.out.println("线程执行"); try { System.out.println("睡一下子"); sleep(180000); } catch (InterruptedException e) { System.out.println("cao ,谁在打扰我睡觉呢!"); } } } public static void main(String[] args) { B b = new B() ; b.start(); int i=0; while(i < 100000000){ i++; } System.out.println("别睡了"); b.interrupt(); } }
执行main函数
线程执行
睡一下子
别睡了
cao ,谁在打扰我睡觉呢!
线程执行
睡一下子