zoukankan      html  css  js  c++  java
  • Java线程的启动和停止(一)

    如何构造线程

    在运行线程之前需要先构造线程对象,线程对象的构造需要指定线程所需要的属性,比如:所属线程组、线程优先级、是否为Daemon线程等信息。下面我们看一下,java.lang.Thread中对线程初始化的方法:

    private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize, AccessControlContext acc,
                          boolean inheritThreadLocals) {
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
            //线程名称
            this.name = name;
            //当前线程就是该线程的父线程
            Thread parent = currentThread();
            SecurityManager security = System.getSecurityManager();
            if (g == null) {
                /* Determine if it's an applet or not */
    
                /* If there is a security manager, ask the security manager
                   what to do. */
                if (security != null) {
                    g = security.getThreadGroup();
                }
    
                /* If the security doesn't have a strong opinion of the matter
                   use the parent thread group. */
                if (g == null) {
                    g = parent.getThreadGroup();
                }
            }
    
            /* checkAccess regardless of whether or not threadgroup is
               explicitly passed in. */
            g.checkAccess();
    
            /*
             * 是否有访问权限
             */
            if (security != null) {
                if (isCCLOverridden(getClass())) {
                    security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
                }
            }
    
            g.addUnstarted();
            //线程组
            this.group = g;
            //使用父线程的daemon、priority属性
            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 (inheritThreadLocals && parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
            /* Stash the specified stack size in case the VM cares */
            this.stackSize = stackSize;
    
            /* 分配一个线程ID */
            tid = nextThreadID();
        }

    一个 新 构造 的 线程 对象 是 由其 parent 线程 来 进行 空间 分配 的, 而 child 线程 继承 了 parent 是否 为 Daemon、 优先级 和 加载 资源 的 contextClassLoader 以及 可继承 的 ThreadLocal, 同时 还会 分配 一个 唯一 的 ID 来 标识 这个 child 线程。 至此, 一个 能够 运行 的 线程 对象 就 初始化 好了, 在 堆 内存 中 等待 着 运行。

    我们构造一个Thread thread=new Thread(),打上断点,可以看到thread对象的属性如下:
    image

    如何使用线程

    实现多线程编程的方式主要有两种:一种是继承Thread类,一种是实现Runnable接口,使用继承Thread类最大的局限性是不支持多继承,由于java单继承的特性,为了突破单继承的限制,于是就有了另一个实现方式,就是实现Runnable接口。使用这两种方式创建的线程工作性质是一样的,没有本质的区别。

    继承Thread类

    public class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("我是自定义线程MyThread");
        }
    }

    实现Runnable接口

    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("我是Runnable");
        }
    }

    如何启动线程

    线程对象初始化完成后,调用线程的start()方法就可以启动线程了,start()方法是告诉Java虚拟机,如果线程规划期空闲,应该立即启动调用了start()方法的线程。

    同一个线程不能多次 调用 start() 方法, 否则会出现异常 Exception in thread” main” java. lang. IllegalThreadStateException。

    线程的start()方法,会新启动一个线程,而线程run()方法则是同步等待当前线程调用。

    如何停止线程

    如何判断线程是否停止

    在介绍如何停止线程的知识点前, 先看一下如何判断线程是否停止的状态。 Thread.java类中提供了两个很重要的方法:

    1) this.interrupted(): 判断当前线程是否已经中断

    2) this.isInterrupted(): 判断线程是否已经中断

    那么这两种方法的区别是什么呢? 先来看看 this.interrupted()方法: 判断当前线程是否已经中断,当前线程是指运行 this. interrupted()方法 的 线程。

     public static void main(String[] args) {
            Thread.currentThread().interrupt();
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " 当前线程是否已停止:=" + Thread.interrupted());
            System.out.println(threadName + " 当前线程是否已停止:=" + Thread.interrupted());
    
        }
    main 当前线程是否已停止:=true
    main 当前线程是否已停止:=false

    从执行结果可知 interrupt()方法确实停止了线程,但是第二个判断结果为什么是false呢,通过查看官方文档当解释得知。interrupted() 具有清除状态的功能,所以第二个判断结果为false

    下面我们接着查看 isInterrupted()方法:

    public static void main(String[] args) {
            Thread.currentThread().interrupt();
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " 当前线程是否已停止:=" + Thread.currentThread().isInterrupted());
            System.out.println(threadName + " 当前线程是否已停止:=" + Thread.currentThread().isInterrupted());
    
        }
    
    main 当前线程是否已停止:=true
    main 当前线程是否已停止:=true

    输出的结果都为true,isInterrupted()并未清除状态标志,最后我们得出如下结论:

    1) this.interrupted(): 判断线程终止的状态, 执行后具有将状态标志置为false的功能

    2) this.isInterrupted():判断线程终止的状态,不具有清除状态标志的功能

    try..catch与this.interrupt方法终止线程

    public class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            for (int i = 0; i < 5000; i++) {
                if (interrupted()) {
                    System.out.println(Thread.currentThread().getName() + " 我被停止了,退出循环");
                    break;
                }
                System.out.println(" i=" + (i + 1));
            }
        }
    }
    
    public static void main(String[] args) {
            MyThread thread = new MyThread();
            thread.setName("Thread-interrupt-0");
            thread.start();
            try {
                Thread.sleep(1);
                thread.interrupt();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(" 结束!");
        }
    
    输出结果:
    .....
    i=32
     i=33
     i=34
     i=35
     i=36
     i=37
     i=38
     i=39
     i=40
     i=41
     结束!
    Thread-interrupt-0 我被停止了,退出循环

    过期的 suspend()、 resume() 和 stop()方法终止线程

    suspend()在调用后线程不会释放已经占有的资源,二是占有着资源进入睡眠状态,这样容易引发死锁问题。同样的stop()方法在终止一个线程时不会保证线程的资源正常释放,通常线程没有机会去释放资源,因此会导致程序工作状态的不确定性。

    正是因为 suspend()、 resume() 和 stop() 方法 带来的副作用, 这些方法才被标志位不建议使用的过期方法, 而暂停和恢复可以使用 等待/ 通知机制 来替代。

  • 相关阅读:
    第一个C#程序
    定位网页元素
    盒子模型
    浮动
    css3美化网页元素
    html css3
    java表单基础
    表单
    html5基础
    java程序题目解析
  • 原文地址:https://www.cnblogs.com/liukaifeng/p/10052601.html
Copyright © 2011-2022 走看看