多线程控制线程的等待和唤醒

最近做注册的时候,发现同步发送注册邮件多了一个耗时,就想到异步处理邮件发送,直接返回成功给用户。

设计了一个线程,用来发送邮件,需要发送的时候再来唤醒就好了,但是对于没有系统了解过多线程的我来说,想的太简单了。

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函数需要一个锁;

研究了一下生产者和消费者,这里用到的锁是对象实例

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方法中创建的实例对象

所以问题又来了,我需要在主线程中启动分线程,所以不能给两个线程分配同一个实例对象,如果每次都重新分配一个实例对象,再创建一个分线程,是不是太愚蠢了;

对于静态方法和非静态方法的同步问题,静态方法锁住的是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 ,谁在打扰我睡觉呢!
线程执行
睡一会儿

 

 

转载于:https://www.cnblogs.com/yangchengInfo/p/3640429.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值