第一节 Java线程简介

亮子 2021-09-14 21:32:22 10807 0 0 0

1、线程有哪几种状态?

public enum State {
        // 1、新建状态
        NEW,

        // 2、运行状态
        RUNNABLE,

        // 3、阻塞状态
        BLOCKED,

        // 4、等待状态
        WAITING,

        // 5、等待超时
        TIMED_WAITING,

        // 6、终止状态
        TERMINATED;
    }

2、线程和进程有啥区别?

1)、一个进程至少有一个线程,一个进程也可以包含多个线程

2)、线程不能够独立存在,必须依赖进程

3)、线程是CPU调度的基本单位(网络分时操作系统,20纳秒)

图片alt

3、线程的优先级

    // 线程最低运行级别
    public final static int MIN_PRIORITY = 1;

    // 默认运行级别
    public final static int NORM_PRIORITY = 5;

    // 最高运行级别
    public final static int MAX_PRIORITY = 10;

4、线程的创建有哪些方式?

1)、继承Thread类

package com.shenmazong;

/**
 * @program: server-java-demo
 * @description: ThreadMethod1
 * @author: 亮子说编程
 * @create: 2020-10-14 20:20
 **/

class ThreadDemo extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("i="+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadMethod1 {

    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.start();
    }
}

2)、实现Runnable接口

package com.shenmazong;

/**
 * @program: server-java-demo
 * @description: ThreadMethod2
 * @author: 亮子说编程
 * @create: 2020-10-14 20:24
 **/


class ThreadRunnable implements Runnable {

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("i="+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadMethod2 {

    public static void main(String[] args) {

        //--1 创建线程
        Thread thread = new Thread(new ThreadRunnable());

        //--2 运行线程
        thread.start();
    }
}

3)、实现Callable接口

package com.shenmazong;

import java.util.concurrent.*;

/**
 * @program: server-java-demo
 * @description: ThreadMethod3
 * @author: 亮子说编程
 * @create: 2020-10-14 20:33
 **/

class ThreadCallable implements Callable<Integer> {
    public Integer call() throws Exception {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+",i="+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return 0;
    }
}

public class ThreadMethod3 {

    public static void main(String[] args) {

        //--1 创建对象
        ThreadCallable threadCallable = new ThreadCallable();

        //--2 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(1);

        //--3 提交运行
        Future<Integer> submit = executorService.submit(threadCallable);

        //--4 获取结果
        Integer result = null;
        try {
            result = submit.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        //--5 销毁线程池
        executorService.shutdownNow();

        System.out.println("result="+result);
    }
}

5、实现Runnable接口和实现Callable接口的区别:

  • Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的。
  • Callable规定的方法是call(),Runnable规定的方法是run()。
  • Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void)。
  • call方法可以抛出异常,run方法不可以。
  • 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
  • 加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法。

6、线程的常用方法

1)、sleep睡眠函数

    /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public static native void sleep(long millis) throws InterruptedException;

2)、yield礼让函数

    /**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     *
     * <p> Yield is a heuristic attempt to improve relative progression
     * between threads that would otherwise over-utilise a CPU. Its use
     * should be combined with detailed profiling and benchmarking to
     * ensure that it actually has the desired effect.
     *
     * <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     */
    public static native void yield();

3)、start启动函数

    /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    public synchronized void start() {
        // ...
    }

4)、run工作函数

    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

5)、exit退出函数

    /**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
    private void exit() {
        if (group != null) {
            group.threadTerminated(this);
            group = null;
        }
        /* Aggressively null out all reference fields: see bug 4006245 */
        target = null;
        /* Speed the release of some of these resources */
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }

6)、isAlive检查存活状态

    /**
     * Tests if this thread is alive. A thread is alive if it has
     * been started and has not yet died.
     *
     * @return  <code>true</code> if this thread is alive;
     *          <code>false</code> otherwise.
     */
    public final native boolean isAlive();

7)、优先级函数

    public final void setPriority(int newPriority) {
        // ...
    }
    public final int getPriority() {
        return priority;
    }

8)、线程名称相关函数

    // 设置线程名字
    public final synchronized void setName(String name) {
        checkAccess();
        this.name = name.toCharArray();
        if (threadStatus != 0) {
            setNativeName(name);
        }
    }
    // 获取线程的名字
    public final String getName() {
        return new String(name, true);
    }

9)、等待线程结束

    /**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }

10)、守护线程

   /**
     * Marks this thread as either a {@linkplain #isDaemon daemon} thread
     * or a user thread. The Java Virtual Machine exits when the only
     * threads running are all daemon threads.
     *
     * <p> This method must be invoked before the thread is started.
     *
     * @param  on
     *         if {@code true}, marks this thread as a daemon thread
     *
     * @throws  IllegalThreadStateException
     *          if this thread is {@linkplain #isAlive alive}
     *
     * @throws  SecurityException
     *          if {@link #checkAccess} determines that the current
     *          thread cannot modify this thread
     */
    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

    /**
     * Tests if this thread is a daemon thread.
     *
     * @return  <code>true</code> if this thread is a daemon thread;
     *          <code>false</code> otherwise.
     * @see     #setDaemon(boolean)
     */
    public final boolean isDaemon() {
        return daemon;
    }

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)。
用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:

只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。

注意:
(1) thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。
(2) 在Daemon线程中产生的新线程也是Daemon的。
(3) 不要认为所有的应用都可以分配给Daemon来进行服务,比如读写操作或者计算逻辑。