美文网首页
Thread机制与源码分析

Thread机制与源码分析

作者: 铁甲依然在_978f | 来源:发表于2018-01-24 04:40 被阅读0次

    线程定义

    线程是现代操作系统调度的最小单元,一个进程可以创建多个线程来提高系统的吞吐量和执行效率。

    :进程是操作系统资源分配和调度的基本单位,它可以创建多个线程,进程可创建的线程数量跟操作系统相关。

    为什么要使用多线程?

    • 更多的处理器核心;
    • 更快的响应时间;
    • 更好的编程模型:java提供了一套完整的jmm规则,屏蔽了底层的一些操作,开发人员只需要关注自己的业务逻辑即可。

    线程的状态

    • NEW:初始状态,线程被构建,还未调用start()方法;
    • RUNNABLE:运行状态,在java多线程模型中,就绪和运行都是运行状态;
    • BLOCKED:阻塞状态;
    • WAITING:等待状态,比如中断,需要其他的线程来唤醒;
    • TIME_WAITING:超时等待,可以在指定的时间内自行返回;
    • TERMINATED:终止状态,线程执行完毕。

    Thread源码分析

    • 构造线程

    构造函数:

    //无参构造方法
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    
    //带参构造方法
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    
    public Thread(String name) {
        init(null, null, name, 0);
    }
    
    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }
    
    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }
    
    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }
    
    public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
        init(group, target, name, stackSize);
    }
    

    所有的构造方法都调用了init这个方法,接下来我们就来详细的看看init方法到底是怎么来初始化线程的。

    初始化线程:

    private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
        //参数校验,线程name不能为null
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        this.name = name.toCharArray();
        //当前线程就是该线程的父线程
        Thread parent = currentThread();
        //获取系统的security
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            //security不为null时,线程所在group为security的group
            if (security != null) {
                g = security.getThreadGroup();
            }
            //security为null时,直接使用父线程的group
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }
        g.checkAccess();
    
        //授权
        if (security != null) {
            if (isCCLOverridden(getClass())) {            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        g.addUnstarted();
        this.group = g;
        //将守护线程、优先级等设置为父线程的对应属性
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (parent.inheritableThreadLocals != null)
            //创建线程共享变量副本
            this.inheritableThreadLocals =         ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        this.stackSize = stackSize;
        //分配线程id
        tid = nextThreadID();
    }
    

    • 启动线程
    public synchronized void start() {
        //假若当前线程初始化还未做好,不能start,0->NEW状态
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
    
        //通知group该线程即将启动,group的未启动线程数量减1
        group.add(this);
    
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                //启动不成功,group设置当前线程启动失败
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
    
            }
        }
    }
    

    启动线程其实做了这么几件事:

    1. 检查线程是否初始化;
    2. 通知group,线程启动;
    3. 调用native方法start0()启动线程,启动后执行run()方法;
    4. 启动失败容错处理。

    • 线程中断
      中断可以理解为一个标识位的属性,它标识一个运行中的线程是否被其他线程进行了中断操作。

    中断线程:

    public void interrupt() {
        //中断其他线程,需要先判断当前线程是否允许修改其他线程
        if (this != Thread.currentThread())
            checkAccess();
        //中断该线程
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();//设置中断标识位
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
    

    查看当前线程是否被中断:

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    

    查看线程是否被中断,已中断返回false

    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    

    • 线程的暂停、恢复和停止

    : 这几个操作都加有@Deprecated注解,不推荐程序员使用

    暂停:

    //可能会造成死锁
    @Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }
    

    恢复:

    //可能会造成死锁
    @Deprecated
    public final void resume() {
        checkAccess();
        resume0();
    }
    

    停止:

    @Deprecated
    public final synchronized void stop(Throwable obj) {
        if (obj == null)
            throw new NullPointerException();
    
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if ((this != Thread.currentThread()) ||
                (!(obj instanceof ThreadDeath))) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        //线程还未初始化好,暂停该线程
        if (threadStatus != 0) {
            resume(); 
        }
    
        //jvm处理线程相关内容
        stop0(obj);
    }
    

    • 线程优先级设置
    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }
    

    需要注意的是:线程优先级不能作为程序正确性的依赖,操作系统有线程优先级的设定,不以程序设定的优先级为准!

    相关文章

      网友评论

          本文标题:Thread机制与源码分析

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