美文网首页
多线程基础知识

多线程基础知识

作者: 江江的大猪 | 来源:发表于2017-11-05 18:11 被阅读41次

    线程状态

    线程调用start()方法开始后,就进入到可运行状态,随着CPU的资源调度在运行和可运行之间切换;

    WX20171107-112550@2x.png

    Thread类常见方法

    • Thread.currentThread()

    返回正在执行的线程对象

    • Thread.yield()

    暂停当前线程,线程们重新抢cpu时间片,也有可能是当前线程又抢到了

    • isAlive()

    实例方法,判断某个线程是否还活着

    • interrupt()

    实例方法,将某个线程的中断标志位置位

    • isInterrupted()

    实例方法,判断某个线程是否被中断

    • Thread.interrupted()

    源码为:return currentThread().isInterrupted(true),返回当前线程是否被中断,并清除标志位

    • Thread.sleep()

    响应中断,抛出InterruptedException异常

    • join()

    实例方法,调用该语句的线程等待执行join()的线程结束再运行,如果join(int)则表示会有最长等待时间,无参则是无限等待,源码为:

            while (isAlive()) {
                wait(0);
            }
    
    • setDaemon(true)

    实例方法,设置某个线程为守护线程,在start()之前设置才有效,否则会抛出异常

    • setPriority()

    实例方法,设置某个线程的优先级,MIN_PRIORITY(1)、NORM_PRIORITY(5)、MAX_PRIORITY(10)。高优先级会更高概率被唤醒、获得锁

    PS:
    Object.wait()、notify()、notifyAll()方法执行前当前线程必须先获得该Object的monitor,也就是必须在同步方法或同步代码块中使用。wait会释放该锁

        public void run() {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                //TODO
                try {
                    Thread.sleep(200);//sleep方法在睡眠中接收到interrupt()方法后会抛出InterruptedException异常并清除interrupt标志位
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    

    volatile和synchronized

    这两个关键字的原理太复杂了,volatile通过lock汇编指令保证了变量操作的可见性。synchronized通过monitor保证了临界区的线程安全。
    volatile关键字可以保证return value和value=xx这两个操作是原子并可见的。理解volatile最好的方法就是,对volatile变量的读写看做使用synchronized做了同步,即便是64位的long和double都是同步的。


    原子类

    • AtomicReference

    get()和set()和直接使用volatile变量的读写一样,更重要的是AtomicReference提供了其他的方法。比如compareAndSet,当要设置的新值和老值有关时,使用volatile就不够了。

    • AtomicIntegerArray

    将数组中的每一个整数都当做AtomicInteger使用,操作都是线程安全的

    • AtomicIntegerFieldUpdater

    让普通类中的普通int属性(必须是volatile的)也享受原子操作:

        Person person = new person();
        //将person对象中的name成员包装
        AtomicIntegerFieldUpdater<Person> updater = AtomicIntegerFieldUpdater.newUpdater(Person.class, "name");
        updater.incrementAndGet(person);
    
    • AtomicLongFieldUpdater、AtomicReferenceFieldUpdater类似

    定时器Timer

    Timer的作用是设置定时任务,但封装任务的类是TimerTask,需要程序员继承TimerTask这个抽象类,实现run()方法,放入自己的业务代码。


    使用Timer
    1. Timer timer = new Timer()

    构造TImer定时器,可以传入boolean参数,true将定时任务设置为守护线程,无参则不设置

    1. 构建TimerTask实例

    一般都是使用匿名类

    TimerTask task = new TimerTask() {   
        public void run() {   
            ... //每次需要执行的业务代码
            cancel();//可以退出调度
        }   
    };
    
    1. schedule调度定时任务

      • timer.schedule(task, time);// time为Date类型:在指定时间执行一次。
      • timer.schedule(task, firstTime, period);// firstTime为Date类型,period为long,从firstTime时刻开始,每隔period毫秒执行一次
      • timer.schedule(task, delay);// delay 为long类型,从现在起过delay毫秒执行一次
      • timer.schedule(task, delay, period);// delay为long,period为long,从现在起过delay毫秒以后,每隔period毫秒执行一次
      • 当任务执行时间小于period时,下次执行时间是上次执行开始时间+peirod;当任务执行时间大于period的话,下次执行时间是上次执行完毕时间+peirod,该定时任务没有并发
    2. scheduleAtFixedRate调度定时任务

      • timer.scheduleAtFixedRate(task, delay, period);// delay为long,period为long,从现在起过delay毫秒以后,每隔period毫秒执行一次
      • timer.scheduleAtFixedRate(task, firstTime, period);// firstTime为Date类型,period为long,从firstTime时刻开始,每隔period毫秒执行一次
      • 当任务执行时间小于period时,下次执行时间是上次执行开始时间+peirod;当任务执行时间大于period的话,下次执行时间是上次执行开始时间+peirod,该定时任务有并发,需要考虑线程安全问题
    3. cancel取消全部定时任务

    和TimerTask的cancel不同,将全部定时任务都取消

    • tips

    schedule和scheduleAtFixedRate当任务执行时间大于period的时候有区别如上。启动时间如果小于当前时间schedule会立即执行,并把当前时间作为参考点,scheduleAtFixedRate会把之前需要执行的次数补上,并将设置的启动时间作为参考点
    timer的原理及缺陷

    肥肥小浣熊

    相关文章

      网友评论

          本文标题:多线程基础知识

          本文链接:https://www.haomeiwen.com/subject/kmrhmxtx.html