多线程学习

来源:互联网 发布:pokemon go挂机软件 编辑:程序博客网 时间:2024/06/16 12:48

一、概念

Java给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径。

多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。
这里定义和线程相关的另一个术语:进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。

多线程能满足程序员编写非常有效率的程序来达到充分利用CPU的目的,因为CPU的空闲时间能够保持在最低限度。

有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。

通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。

请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU花费在上下文的切换的时间将多于执行程序的时间!

线程的生命周期

线程经过其生命周期的各个阶段。下图显示了一个线程完整的生命周期。

这里写图片描述

  • 新建状态: 一个新产生的线程从新状态开始了它的生命周期。它保持这个状态直到程序start这个线程。
  • 运行状态: 当一个新状态的线程被start以后,线程就变成可运行状态,一个线程在此状态下被认为是开始执行其任务
  • 就绪状态: 当一个线程等待另外一个线程执行一个任务的时候,该线程就进入就绪状态。当另一个线程给就绪状态的线程发送信号时,该线程才重新切换到运行状态。
  • 休眠状态: 由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。当时间间隔到期或者等待的时间发生了,该状态的线程切换到运行状态。
  • 终止状态: 一个运行状态的线程完成任务或者其他终止条件发生,该线程就切换到终止状态。

线程的优先级

每一个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。Java优先级在MIN_PRIORITY(1)和MAX_PRIORITY(10)之间的范围内。默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器时间。然而,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。

二、创建一个线程

Java提供了两种创建线程方法:
- 通过实现Runnable接口。
- 通过继承Thread类本身。

通过实现Runnable接口来创建线程

创建一个线程,最简单的方法是创建一个实现Runnable接口的类。

为了实现Runnable,一个类只需要执行一个方法调用run(),声明如下:

public void run()

你可以重写该方法,重要的是理解的run()可以调用其他方法,使用其他类,并声明变量,就像主线程一样。
在创建一个实现Runnable接口的类之后,你可以在类中实例化一个线程对象。
Thread定义了几个构造方法,下面的这个是我们经常使用的:

Thread(Runnable threadOb,String threadName);

这里,threadOb 是一个实现Runnable 接口的类的实例,并且 threadName指定新线程的名字。

新线程创建之后,你调用它的start()方法它才会运行。

void start();

demo

public class TestThread {    @Test    public void testThread(){        for (int i = 0; i < 10; i++) {            Thread thread = new Thread(new createRunnableThread(i), String.valueOf(i));            thread.start();        }    }// java7写法//    private Runnable createRunnableThread(int i) {//        return new Runnable() {//            @Override//            public void run() {//                System.out.println(i);//            }//        };//    }// java8写法    private Runnable createRunnableThread(int i) {        return () -> System.out.println(i);    }}

通过继承Thread来创建线程

创建一个线程的第二种方法是创建一个新的类,该类继承Thread类,然后创建一个该类的实例。

继承类必须重写run()方法,该方法是新线程的入口点。它也必须调用start()方法才能执行。

demo

public class TestThread {    @Test    public void testThread() throws InterruptedException {        for (int i = 0; i < 10; i++) {            Thread thread = new Thread(new createThread(i), String.valueOf(i));            thread.start();        }    }}class createThread extends Thread {    private int i = 0;    createThread(int i) {        this.i = i;    }    public void run() {        System.out.println(i);    }}

三、Thread 方法

方法 描述 start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。 setName(String name) 改变线程名称,使之与参数 name 相同。 setPriority(int priority) 更改线程的优先级。 setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。 interrupt() 中断线程。 isAlive() 测试线程是否处于活动状态。

上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。

方法 描述 yield() 暂停当前正在执行的线程对象,并执行其他线程。 sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 holdsLock(Object x) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 currentThread() 返回对当前正在执行的线程对象的引用。 dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。

四、工具类

public class ThreadPool extends ThreadGroup {    /**     * 线程池是否关闭     */    private boolean isClosed = false;    /**     * 工作队列     */    private LinkedList<Runnable> workQueue;    /**     * 线程池的id     */    private static int threadPoolID = 1;    public ThreadPool(int poolSize) {        //poolSize 表示线程池中的工作线程的数量        //指定ThreadGroup的名称        super(String.valueOf(threadPoolID));        //继承到的方法,设置是否守护线程池        setDaemon(true);        //创建工作队列        workQueue = new LinkedList<>();        for (int i = 0; i < poolSize; i++) {            //创建并启动工作线程,线程池数量是多少就创建多少个工作线程            new WorkThread(i).start();        }    }    /**     * 向工作队列中加入一个新任务,由工作线程去执行该任务     */    public synchronized void execute(Runnable task) {        if (isClosed) {            throw new IllegalStateException();        }        if (task != null) {            //向队列中加入一个任务            workQueue.add(task);            //唤醒一个正在getTask()方法中待任务的工作线程            notify();        }    }    /**     * 从工作队列中取出一个任务,工作线程会调用此方法     */    private synchronized Runnable getTask(int threadid) throws InterruptedException {        while (workQueue.size() == 0) {            if (isClosed) {                return null;            }            //System.out.println("工作线程"+threadid+"等待任务...");            //如果工作队列中没有任务,就等待任务            wait();        }        //System.out.println("工作线程"+threadid+"开始执行任务...");        //反回队列中第一个元素,并从队列中删除        return (Runnable) workQueue.removeFirst();    }    /**     * 关闭线程池     */    public synchronized void closePool() {        if (!isClosed) {            //等待工作线程执行完毕            waitFinish();            isClosed = true;            //清空工作队列            workQueue.clear();            //中断线程池中的所有的工作线程,此方法继承自ThreadGroup类            interrupt();        }    }    /**     * 等待工作线程把所有任务执行完毕     */    private void waitFinish() {        synchronized (this) {            isClosed = true;            //唤醒所有还在getTask()方法中等待任务的工作线程            notifyAll();        }        //activeCount() 返回该线程组中活动线程的估计值。        Thread[] threads = new Thread[activeCount()];        //enumerate()方法继承自ThreadGroup类,根据活动线程的估计值获得线程组中当前所有活动的工作线程        int count = enumerate(threads);        //等待所有工作线程结束        for (int i = 0; i < count; i++) {            try {                //等待工作线程结束                threads[i].join();            } catch (InterruptedException ex) {                ex.printStackTrace();            }        }    }    /**     * 内部类,工作线程,负责从工作队列中取出任务,并执行     */    private class WorkThread extends Thread {        private int id;        private WorkThread(int id) {            //父类构造方法,将线程加入到当前ThreadPool线程组中            super(ThreadPool.this, id + "");            this.id = id;        }        @Override        public void run() {            //isInterrupted()方法继承自Thread类,判断线程是否被中断            while (!isInterrupted()) {                Runnable task = null;                try {                    //取出任务                    task = getTask(id);                } catch (InterruptedException ex) {                    ex.printStackTrace();                }                //如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程                if (task == null) {                    return;                }                try {                    //运行任务                    task.run();                } catch (Throwable t) {                    t.printStackTrace();                }            }        }    }}

测试

public static void main(String[] args) throws InterruptedException {    ThreadPool threadPool = new ThreadPool(3); //创建一个有个3工作线程的线程池    Thread.sleep(500); //休眠500毫秒,以便让线程池中的工作线程全部运行    //运行任务    long start = System.currentTimeMillis();//开始时间    for (int i = 0; i <= 500; i++) { //创建500个任务        threadPool.execute(createTask(i));    }    threadPool.waitFinish(); //等待所有任务执行完毕    long end = System.currentTimeMillis();    System.out.println("总用时 ============:" + (end - start) + "ms");    threadPool.closePool(); //关闭线程池}private static Runnable createTask(final int taskID) {    return new Runnable() {        @Override        public void run() {            System.out.println("Hello world----" + Thread.currentThread() + "------" + taskID);        }    };}
原创粉丝点击