精华内容
下载资源
问答
  • 多线程执行过程(生命周期)

    多线程执行过程(生命周期)
    在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。
    1、新建状态,当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值

    2、就绪状态,当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行

    3、运行状态,如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态

    4、阻塞状态,一个正在运行的线程因某些原因不能继续运行时,就进入阻塞 状态。这些原因包括:
    a) 当执行了某个线程对象的sleep()等阻塞类型的方法时,该线程对象会被置入一个阻塞集内,等待超时而自动苏醒。
    b) 当多个线程试图进入某个同步区域时,没能进入该同步区域的线程会被置入锁定集,直到获得该同步区域的锁,进入就绪状态。
    c) 当线程执行了某个对象的wait()方法时,线程会被置入该对象的等待集中,知道执行了该对象的notify()方法wait()/notify()方法的执行要求线程首先获得该对象的锁。

    5、死亡状态,run()方法执行结束或异常退出的方式:interrupt()或stop()方法。
    线程状态转换图

    展开全文
  • 多线程的两种创建方式,图解对源码进行分析

    首先看一段代码(面试题),看一下执行结果

        public static void main(String[] args) {
            new Thread(new Runnable() {
    
                //重写Runnable下的run方法
                public void run() {
                    System.out.println("number1");
                }
            }) {
                //重写Thread的run方法
                public void run() {
                    System.out.println("number2");
                };
            }.start();
        }

    执行结果:
    这里写图片描述
    看一下下面的两种方式,就会知其所以然了

    第一种方式:继承

    下面我们来分析下面这一段代码的执行流程

    public class ThreadDemo01 {
        public static void main(String[] args) {
            MyThread mt = new MyThread();
            mt.start();
        }
    
    }
    //自定义一个类继承于Thread
    class MyThread extends Thread {
        @Override
        //重写Thread的run方法
        public void run() {
            System.out.println("number2");
        }
    }

    1-创建对象执行过程

    这里写图片描述

    2-start方法执行过程

    这里写图片描述

    3-执行结果

    这里写图片描述

    第二种方式:实现Runnable接口

    下面我们来分析下面这一段代码的执行流程

    public class ThreadDemo01 {
        public static void main(String[] args) {
            //创建实现类对象,并向上转型
            Runnable target = new MyThread();
            //将实现类对象作为参数传入
            Thread mt = new Thread(target);
            mt.start();
        }
    }
    //自定义一个类实现了Runnable接口
    class MyThread implements Runnable {    
        @Override
        //重写Runnable的run方法
        public void run() {
            System.out.println("number1");
        }
    }
    

    1-创建对象执行过程

    这里写图片描述

    2-start方法执行过程

    这里写图片描述

    3-运行结果

    这里写图片描述

    展开全文
  • ![图片说明](https://img-ask.csdn.net/upload/201705/27/1495869780_791343.png) !...!...!...请教,能否按照截图上的分析多线程执行流程的这种方式,分析一下,正确的多个线程的执行流程应该是什么样的? 如有指点,非常感谢.
  • 在编程工作中,我们经常...接下来我们会映照上图介绍多线程执行过程中经历的五种状态: 1. 新建状态: 新建状态就是我们通过new关键字实例化出一个线程类的对象时的状态。 public class IsAThread extends Thre...

    在编程工作中,我们经常会用到或听到多线程三个字,多线程编程的好处就是可以让多个任务进行并发,从而更加充分利用CPU,减少CPU的无效等待时间。

    多线程的执行流程图如下:

    接下来我们会映照上图介绍多线程执行过程中经历的五种状态:

    1. 新建状态:

    新建状态就是我们通过new关键字实例化出一个线程类的对象时的状态。

    public class IsAThread extends Thread{
        @Override
        public void run() {
            System.out.println("这是一个线程类");
        }
    }
    public static void main(String[] args) {
        // 线程进入新建状态
        IsAThread isAThread = new IsAThread();
    }

    此时,我们就说 isAThread 这个线程对象进入了新建状态。

    2. 可运行状态:

    当我们调用了新建状态下的线程对象的 start() 方法来启动这个线程,并且线程对象已经准备好了除CPU时间片段之外的所有资源后,该线程对象会被放入“可运行线程池”中等待CPU分配时间片段给自身。在自身获得CPU的时间片段之后便会执行自身 run() 方法中定义的逻辑,示例中的线程对象的 run() 方法是打印了 “这是一个线程类” 这么一句话到控制台。

    public static void main(String[] args) {
        // 线程进入新建状态
        IsAThread isAThread = new IsAThread();
        // 线程进入可运行状态
        isAThread.start();
    }

    3. 运行状态:

    运行状态的线程在分配到CPU的时间片段之后,便会真正开始执行线程对象 run() 方法中定义的逻辑代码了,示例中的线程对象的 run() 方法是打印了 “这是一个线程类” 这么一句话到控制台。

    1)但是生产环境中的线程对象的 run() 方法一般不会这么简单,可能业务代码逻辑复杂,造成CPU的时间片段所规定的时长已经用完之后,业务代码还没执行完;

    2)或者是当前线程主动调用了Thread.yield()方法来让出自身的CPU时间片段。

    public class IsAThread extends Thread{
        @Override
        public void run() {
            // 主动让出自身获取到的CPU时间片段给其他线程使用
            Thread.yield();
            System.out.println("这是一个线程类");
        }
    }

    此时,运行状态会转回可运行状态,等待下一次分配到CPU时间片段之后继续执行未完成的操作。

    4. 阻塞状态:

    阻塞状态指的是运行状态中的线程因为某种原因主动放弃了自己的CPU时间片段来让给其他线程使用,可能的阻塞类型及原因有:

    4.1 等待阻塞:

    线程被调用了 Object.wait() 方法后会立刻释放掉自身获取到的锁并进入“等待池”进行等待,等待池中的线程被其他线程调用了 Object.notify() 或 Object.notifyAll() 方法后会被唤醒从而从“等待池”进入到“等锁池”,“等锁池”中的线程在重新获取到锁之后会转为可运行状态。

    值得注意的是:wait()和notify()/notifyAll()只能用在被synchronized包含的代码块中,而说明中的Object.wait和Object.notify的这个Object实际上是指作为synchronized锁的对象。

    例如:

    我们创建两个线程类,StringBufferThread和StringBufferThread2,这两个类唯一的不同就是run()方法的实现。

    StringBufferThread:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread implements Runnable {
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            // StringBufferThread这个类作为锁
            synchronized (StringBufferThread.class) {
                sb.append("This is StringBufferThread1\n");
                countDownLatch.countDown();
            }
        }
    }

    StringBufferThread2:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread2 implements Runnable{
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread2(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            // StringBufferThread这个类作为锁
            synchronized (StringBufferThread.class) {
                sb.append("This is StringBufferThread2\n");
                countDownLatch.countDown();
            }
        }
    
    
    }

    main:

        public static void main(String[] args) throws InterruptedException {
            StringBuffer tipStr = new StringBuffer();
            // 使用CountDownLatch保证子线程全部执行完成后主线程才打印结果
            CountDownLatch countDownLatch = new CountDownLatch(2);
            StringBufferThread stringBufferThread = new StringBufferThread(tipStr, countDownLatch);
            StringBufferThread2 stringBufferThread2 = new StringBufferThread2(tipStr, countDownLatch);
            Thread thread1 = new Thread(stringBufferThread);
            Thread thread2 = new Thread(stringBufferThread2);
            thread1.start();
            /*
             为了保证先让thread1执行,我们让thread1执行后主线程睡眠5秒钟再执行thread2,
             如果不进行睡眠的话我们无法控制CPU分配时间片段,有可能直接就先分配给thread2线程了,
             这样就会造成thread2先于thread1执行
              */
            Thread.sleep(5000);
            thread2.start();
            // 调用countDownLatch.await()保证子线程全部执行完后主线程才继续执行
            countDownLatch.await();
            System.out.println(tipStr.toString());
        }

    那么我们先来看一下这种没使用wait()和notify()的情形下,先后执行这两个线程对象时的结果:

    跟逻辑一样,先执行了stringBufferThread然后执行了stringBufferThread2。

    接下来,修改StringBufferThread类:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread implements Runnable {
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            // StringBufferThread这个类作为锁
            synchronized (StringBufferThread.class) {
                try {
                    /*
                     在将字符串追加到StringBuffer前,调用锁对象StringBufferThread这个类的wait(),
                     来使本子线程进行休眠
                      */
                    StringBufferThread.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sb.append("This is StringBufferThread1\n");
                countDownLatch.countDown();
            }
        }
    }

    为StringBufferThread类中的run方法中,将字符串"This is StringBufferThread1\n"加入StringBuffer对象之前,加入wait()方法来进行等待,注意,wait()方法会立刻释放掉自身的锁后,也就是其他争取到锁的线程可以运行被这个synchronized保护的代码块了。

    随后,我们修改StringBufferThread2:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread2 implements Runnable{
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread2(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            // StringBufferThread这个类作为锁
            synchronized (StringBufferThread.class) {
                sb.append("This is StringBufferThread2\n");
                /*
                 在将字符串追加到StringBuffer后,调用锁对象StringBufferThread这个类的notify(),
                 来唤醒本这个锁对象的wait()方法等待的子线程,本例中就是main方法中的stringBufferThread这个子线程
                  */
                StringBufferThread.class.notify();
                countDownLatch.countDown();
            }
        }
    
    
    }

    也就是在字符串"This is StringBufferThread2\n"追加到StringBuffer之后调用了 notify() 方法来唤醒被 StringBufferThread.class 这个锁等待的线程,本例中就是main方法中的stringBufferThread这个子线程,本唤醒的子线程会进入等锁池,等待重新争取到锁之后,会继续执行代码。

    main方法不变,我们来看看执行结果:

    与我们预想的一样,因为thread1在追加字符串到StringBuffer对象之前调用了锁对象的wait(),就立即释放掉了自身获取到的锁并进入等待池中了,这时thread2获取了锁,将字符串"This is StringBufferThread2\n"首先追加到了StringBuffer对象的开头,然后调用锁对象的notify()方法唤醒了thread1,被唤醒的thread1重新获取锁之后,才将自身的字符串"This is StringBufferThread1\n"追加到了StringBuffer对象的末尾。

    4.2 同步阻塞:

    线程执行到了被 synchronized 关键字保护的同步代码时,如果此时锁已经被其他线程取走,则该线程会进入到“等锁池”,直到持有锁的那个线程释放掉锁并且自身获取到锁之后,自身会转为可运行状态。

    例子如下:

    StringBufferThread:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread implements Runnable {
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            // StringBufferThread这个类作为锁
            synchronized (StringBufferThread.class) {
                try {
                    // 睡眠10秒,因为主线程在调用本线程5秒后就会调用第二个子线程,多睡眠5秒,就能看出效果
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sb.append("This is StringBufferThread1\n");
                countDownLatch.countDown();
            }
        }
    }

    StringBufferThread2:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread2 implements Runnable{
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread2(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            // StringBufferThread这个类作为锁
            synchronized (StringBufferThread.class) {
                sb.append("This is StringBufferThread2\n");
                countDownLatch.countDown();
            }
        }
    
    
    }

    main方法不变:

    public static void main(String[] args) throws InterruptedException {
        StringBuffer tipStr = new StringBuffer();
        // 使用CountDownLatch保证子线程全部执行完成后主线程才打印结果
        CountDownLatch countDownLatch = new CountDownLatch(2);
        StringBufferThread stringBufferThread = new StringBufferThread(tipStr, countDownLatch);
        StringBufferThread2 stringBufferThread2 = new StringBufferThread2(tipStr, countDownLatch);
        Thread thread1 = new Thread(stringBufferThread);
        Thread thread2 = new Thread(stringBufferThread2);
        thread1.start();
        /*
         为了保证先让thread1执行,我们让thread1执行后主线程睡眠5秒钟再执行thread2,
         如果不进行睡眠的话我们无法控制CPU分配时间片段,有可能直接就先分配给thread2线程了,
         这样就会造成thread2先于thread1执行
          */
        Thread.sleep(5000);
        thread2.start();
        // 调用countDownLatch.await()保证子线程全部执行完后主线程才继续执行
        countDownLatch.await();
        System.out.println(tipStr.toString());
    }

    执行结果如下:

    由此可见,主线程调用thread1后的5秒后调用了thread2,thread1在执行时首先拿走了锁对象并睡眠了10秒,在这10秒钟,thread2有5秒的时间(10秒减去主线程等待的5秒)去执行run方法中的字符串追加操作,但是因为锁已经被thread1拿走了,所以thread2在这漫长的5秒钟之内什么都做不了,只能等待thread1将字符串"This is StringBufferThread1\n"先追加到StringBuffer的开头,然后才能把自己的字符串"This is StringBufferThread2\n"追加到StringBuffer的末尾。

    4.3 其他阻塞:

    1)线程中执行了 Thread.sleep(xx) 方法进行休眠会进入阻塞状态,直到Thread.sleep(xx)方法休眠的时间超过参数设定的时间而超时后线程会转为可运行状态。Thread.sleep(xx)方法的使用在本文很多例子都体现了,就不演示了。

    2)线程ThreadA中调用了ThreadB.join()方法来等待ThreadB线程执行完毕,从而ThreadA进入阻塞状态,直到ThreadB线程执行完毕后ThreadA会转为可运行状态。

    例子如下:

    StringBufferThread:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread implements Runnable {
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
        Thread thread2;
    
    
        StringBufferThread(StringBuffer sb, CountDownLatch countDownLatch, Thread thread2) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
            this.thread2 = thread2;
        }
    
        @Override
        public void run() {
            try {
                // 这里阻塞住,等待thread2执行完毕才会继续向下执行
                thread2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sb.append("This is StringBufferThread1\n");
            countDownLatch.countDown();
        }
    }

    StringBufferThread2:

    import java.util.concurrent.CountDownLatch;
    
    public class StringBufferThread2 implements Runnable {
    
        StringBuffer sb;
        CountDownLatch countDownLatch;
    
    
        StringBufferThread2(StringBuffer sb, CountDownLatch countDownLatch) {
            this.sb = sb;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            /*
             thread2睡眠3秒,就能看出效果,如果join()失效,
             那么StringBuffer中一定是"This is StringBufferThread1\n"开头的
              */
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sb.append("This is StringBufferThread2\n");
            countDownLatch.countDown();
        }
        
    }

    随后,修改main方法:

    public static void main(String[] args) throws InterruptedException {
        StringBuffer tipStr = new StringBuffer();
        // 使用CountDownLatch保证子线程全部执行完成后主线程才打印结果
        CountDownLatch countDownLatch = new CountDownLatch(2);
        StringBufferThread2 stringBufferThread2 = new StringBufferThread2(tipStr, countDownLatch);
        Thread thread2 = new Thread(stringBufferThread2);
        StringBufferThread stringBufferThread = new StringBufferThread(tipStr, countDownLatch, thread2);
        Thread thread1 = new Thread(stringBufferThread);
        thread1.start();
        thread2.start();
        // 调用countDownLatch.await()保证子线程全部执行完后主线程才继续执行
        countDownLatch.await();
        System.out.println(tipStr.toString());
    }

    执行结果如下:

    由此可见,虽然thread1先于thread2执行,但是因为在将字符串追加到StringBuffer对象前调用了thread2.join(),便被阻塞住了,此时thread2睡眠三秒后,将字符串"This is StringBufferThread2\n"追加到了StringBuffer对象的开头,thread2执行完毕;随后因为thread1等待的thread2已经执行完毕了,thread1便由阻塞状态转为可运行状态,在分配到CPU的时间片段后,便将字符串"This is StringBufferThread1\n"追加到了StringBuffer对象的结尾。

    3)线程中进行了I/O操作,I/O操作在输入输出行为执行完毕之前都不会返回给调用者任何结果,直到I/O操作执行完毕之后线程会转为可运行状态。

    例如:

    我们编写ThreadTest类:

    import java.util.Scanner;
    
    public class ThreadTest implements Runnable {
    
        @Override
        public void run() {
            System.out.println("This is StringBufferThread1 Begin\n");
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入内容:");
            // 线程会阻塞在这,等待用户在控制台输入数据后继续执行
            String content = scanner.nextLine();
            System.out.println("您输入的内容是:" + content + "\n");
            System.out.println("This is StringBufferThread1 end\n");
        }
    
    }
    

    执行main方法:

    public static void main(String[] args) throws InterruptedException {
        ThreadTest threadTest = new ThreadTest();
        Thread thread1 = new Thread(threadTest);
        thread1.start();
    }

    执行效果如下:

    线程会阻塞在这里等待我们从控制台输入内容。

    输入内容后,线程继续运行。

    展开全文
  • 多线程执行框架Executor详解

    千次阅读 2014-12-13 14:49:29
    为了能够更好的进行多线程编程,JDK提供了一套Executor执行框架,简化开发人员的对多线程的编程工作。 其框架结构图如下: 框架图比较庞大,但我们只需要关注如下几个实现: Executor接口:只有一个 execute ...

    为了能够更好的进行多线程编程,JDK提供了一套Executor执行框架,简化开发人员的对多线程的编程工作。

    其框架结构图如下:



    框架图比较庞大,但我们只需要关注如下几个实现:

    • Executor接口:只有一个 execute 方法,用来接收一个可执行对象。
    • ExecutorService接口:表示具有接收任务功能。
    • ThreadPoolExecutor:表示一个线程池,当然它比我们之前写过的线程池 ThreadPool复杂的多。http://blog.csdn.net/zq602316498/article/details/41819489
    • Executors类:线程池工厂,通过它可以取得一个特定功能的线程池。
    • ScheduleExecutorService:可以指定时间或周期执行的线程池。

    我们平时用的最多的便是 Executors工厂类,这个工厂类提供了能产生多个不同功能线程池的方法。

    • newFixedThreadPool() 方法:具有固定数量的线程池,线程数量始终不变。当有一个新任务提交时,线程中若有空闲进程变会执行它。若没有,则新的任务会被暂停在一个任务队列中。
    • newCachedThreadPool() 方法:线程数量不固定,当线程不足时便会产生新的线程。
    • newSingleThreadExecutor()方法:只有一个线程的线程池,按先进先出的顺序执行队列中的任务。
    • newSingleThreadScheduledExecutor() 方法:只有一个线程的线程池,但是可以指定执行时间或执行周期
    • newScheduleThreadPool()方法:同上一个方法,只不过可以指定线程数量

    自定义线程池

    newFixedThreadPool()、newSingleThreadExecutor()和newCachedThreadPool()方法其内部都使用了 ThreadPoolExecutor线程池。

    public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>(),
                                          threadFactory);
        }
    public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }

    我们可以看到,以上线程池都只是 ThreadPoolExecutor 类的封装。这是一个比较复杂的类,我们通过构造函数来慢慢了解它。

        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler)

    • corePoolSize:线程池线程数量
    • maxMumPoolSize:最大线程数量
    • keepAliveTime:超过corePoolSize数量的线程的存活时间
    • unit: keepAliveTime的单位
    • workQueue:任务队列,保存了被提交但是未被执行的任务
    • threadFactory:用于创建线程的线程工厂

    workQueue用来盛放被提交但未执行的任务队列,它是一个BlockingQueue 接口的对象,仅用于存放 Runnable对象。可以使用以下一种阻塞队列
    直接提交队列:由SynchronousQueue 对象提供。即每一次提交任务时,如果没有空闲的线程,就会提交失败或者执行拒绝策略。因此,此时要设置很大的maximumPoolSize值。
    有界的任务队列:可以使用 ArrayBlockingQueue。这时,如果有新任务需要执行,且实际线程数小于corePoolSize 时,会优先创建线程。若大于corePoolSize,则会将任务加入等待队列。若队列已满,则会创建新线程且保证线程数不大于 maximumPoolSize。若大于 maximumPoolSize,则执行拒绝策略。
    无界任务队列:使用 LinkedBlockingQueue 类实现。和有界任务队列类似,只不过系统线程数到达corePoolSize后就不在增加。后续任务都会放入阻塞队列中,直到耗尽系统资源。
    优先任务队列: 通过 PriorityBlockingQueue 实现。可以控制任务的执行先后顺序,是一个特殊的无界队列。

    ThreadPoolExecutor 最后一个参数 handler 指定了拒绝策略,有如下几种:

    • AbortPolicy策略:直接抛出异常,阻止系统正常工作。
    • CallerRunsPolicy策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。
    • DiscardOledestPolicy策略:丢弃最老的一个请求(即将被执行的任务),并尝试再次提交当前任务。
    • DiscardPolicy策略:丢弃无法处理的任务,不作任何处理。

    以上拒绝策略都实现了 RejectedExecutionHandler 接口,我们也可以扩展这个接口来实现自己的拒绝策略。

    下面,我们使用优先队列自定义线程池来实现具有优先级调度功能的线程池。使用优先队列时,任务线程必须实现 Comparable 接口。

    package executor;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.PriorityBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class MyThread implements Runnable,Comparable<MyThread>{
    	private String name;
    	public MyThread(String name){
    		this.name=name;
    	}
    	public MyThread(){
    		name="";
    	}
    	
    	@Override
    	public void run(){
    		try{
    			Thread.sleep(100);
    			System.out.println(name+" running....");
    		}catch(InterruptedException e){
    			e.printStackTrace();
    		}
    	}
    	@Override
    	public int compareTo(MyThread o){
    		int me = Integer.valueOf(name.split("_")[1]);
    		int other = Integer.valueOf(o.name.split("_")[1]);
    		return me-other;
    	}
    	
    	public static void main(String[] args){
    		Executor exe = new ThreadPoolExecutor(100, 100, 0L, TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>());
    		for(int i =0;i<1000;i++){
    			exe.execute(new MyThread("testThread_"+(999-i)));
    		}
    		
    	}
    }
    

    输出如下:

    testThread_998 running....
    testThread_999 running....
    testThread_993 running....
    testThread_995 running....
    testThread_997 running....
    。。。
    testThread_912 running....
    testThread_900 running....
    testThread_910 running....
    testThread_1 running....
    testThread_2 running....
    testThread_3 running....
    testThread_4 running....
    testThread_0 running....

    可以看到,900-999号线程是任务提交时,未经过优先队列而直接被执行的任务(程序刚运行时有大量的空闲进程100个,无需使用等待队列),之后是经过优先队列中转之后被执行的任务。可以看到,优先级较高的任务(数字越小,优先级越高)优先被执行。

    扩展ThreadPoolExecutor

    ThreadPoolExecutor 也是一个可以扩展的线程池,它提供了 beforeExecute()、afterExecute()和terminated()3个接口对其进行控制。

    在 Worker.runWorker() 的方法内部提供了这样一个调用过程:

    try {
                        beforeExecute(wt, task);
                        Throwable thrown = null;
                        try {
                            task.run();
                        } catch (RuntimeException x) {
                            thrown = x; throw x;
                        } catch (Error x) {
                            thrown = x; throw x;
                        } catch (Throwable x) {
                            thrown = x; throw new Error(x);
                        } finally {
                            afterExecute(task, thrown);
                        }
                    } finally {
                        task = null;
                        w.completedTasks++;
                        w.unlock();
                    }

    ThreadPoolExecutor.Worker 是默认的工作线程,在其执行过程中,提供了空的 beforeExecute() 和 afterExecute() 的实现。实际应用中,可以对其进行拓展,实现对线程池运行状态的跟踪,输入一些有用的调试信息,以帮助系统故障诊断。

    class MyThreadPoolExecutor extends ThreadPoolExecutor {
    	public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
    			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    	}
    
    	protected void beforeExecute(Thread t, Runnable r) {
    		System.out.println("beforeExecute MyThread name:" + t.getName()
    				+ " ID:" + t.getId());
    	}
    
    	protected void afterExecute(Runnable r, Throwable t) {
    		System.out.println("afterExecute MyThread name:" + Thread.currentThread().getName() + " ID:"
    				+ Thread.currentThread().getId());
    		System.out.println("afterExecute PoolSize:" + this.getPoolSize());
    	}
    }

    以上代码实现了一个带有日志输出功能的线程池,该线程池会在任务执行前输入即将要执行的任务名称和线程ID,同时会在任务完成后,输出线程的 ID 和当前线程池的线程数量。
    展开全文
  • 线程执行流程

    千次阅读 2020-04-05 13:02:43
    线程执行流程
  • C#多线程之所有线程执行完成后

    千次阅读 2017-07-28 10:24:09
    多线程的应用开发过程中,我们可能会遇到某些任务需要等待所有线程执行完成后,再进行处理。搜了下关于这方面的解决方案,在这里不做细说。 今天主要是想说下C#多线程中,可以利用ManualResetEvent对象,结合...
  • OC中多线程执行顺序的控制

    千次阅读 2016-05-16 10:49:00
    GCD时基于C语音开发的一套多线程开发机制,时完全面向过程的。GCD统一管理整个队列中的任务。GCD队列分为并行队列和串行队列。 串行队列:只有一个线程,加入到队列中的操作按添加顺序依次执行。 并发队列:有多个...
  • 多线程执行时间的差异

    千次阅读 2017-08-13 09:08:07
    在Java当中,多线程执行时间是非顺序,这个究竟是怎么回事? 举例代码: public class ICurrentThread extends Thread { @Override public void run(){ super.run(); System.out.println("this is my thread")...
  • JUnit4多线程执行测试用例

    万次阅读 2015-05-07 09:36:09
    在testerhome社区中,有人评论说直接使用TestNG,就可以实现多线程,是的,但是方式不一样;我们是按照自己的需求对JUnit4自定义多线程Runner,直接在某个类加上相应的注解即可,运行该类就行,支持类和方法级别;...
  • 使用spring+ibatis框架开发; 现在网站的下单流程分为三步,1、发送邮件和...现在用线程池来实现多线程的并发操作。但是如果其中一个线程出现异常,想的是应该全 部都回滚。那么如果来保证这三个线程之间的原子性。
  • 对事件发布订阅模式中启动线程执行操作,但又要保证线程顺序执行的一些思考和实践,在开发过程中,经常会遇到需要使用事件来触发方法执行的情况,比如CS中按钮的点击事件,鼠标移动事件,键盘监听事件等等,有时候...
  • 多线程优化执行效率

    千次阅读 2018-09-21 20:59:35
    文章目录普通任务多线程同步任务代码多线程异步任务总结CountDownLatch特性AtomicInteger特性 在项目开发中,碰到了一些耗时任务的问题. 需要使用多线程,本文在使用原生JDK7的情况下优化 (不考虑JAVA8和RxJava框架) ...
  • 如何控制多线程执行顺序

    千次阅读 2019-06-19 18:18:22
    static Thread thread1 = new Thread(new Runnable() { @Override public void run() { System.out.println("线程1"); } }); static Thread thread2 = new Thread(n...
  • 万字图解Java多线程

    万次阅读 多人点赞 2020-09-06 14:45:07
    java多线程我个人觉得是javaSe中最难的一部分,我以前也是感觉学会了,但是真正有多线程的需求却不知道怎么下手,实际上还是对多线程这块知识了解不深刻,不知道多线程api的应用场景,不知道多线程的运行流程等等,...
  • 多线程执行CPU过高问题

    万次阅读 2014-09-26 11:23:48
    在项目开发过程中使用到多线程技术,但
  • Python 多线程操作操作,线程2不执行

    千次阅读 2019-03-03 16:48:19
    问题:在多线程操作过程中,线程1中的有死循环,在执行过程中,线程2一直不执行。 Code before update import threading import time class test(): def print_111(self): while 1: pri...
  • PHP开启异步多线程执行脚本

    万次阅读 2013-11-27 10:40:58
    场景要求 客户端调用服务器a.php...客户端调用a.php之后,a.php执行异步多线程操作调用b.php,a.php调用成功后即刻反馈给客户端回执,b.php自动执行耗资源操作。 难点 PHP没有真正实现多线程操作的方法。所以需要通
  • 获取线程运行时异常 在Thread类中,关于处理运行时异常的API 总共有四个 //为某个特定线程指定 UncaughtExceptionHandler public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) //设...
  • java 多线程顺序执行

    千次阅读 2019-06-14 16:22:44
    这道阿里巴巴多线程面试题,你学会了没有? 置顶2019年06月14日 15:43:55XingXing_Java阅读数 447 点关注,不迷路;持续更新Java相关技术及资讯!!! 前言 有个朋友问了我一道面试阿里的时候遇到的多线程...
  • Springboot+多线程+等待获取执行结果

    千次阅读 2020-08-06 14:12:52
    在日常的开发项目过程中,时常会有多线程的使用场景。最近开发的需求中也是如此,只不过这次需要开启多线程执行,最后要等所有线程结束统一获取结果。所以在此整理一下 在springboot项目中开启异步线程需要满足...
  • 狭义定义:进程就是一段程序的执行过程 简单的来讲进程的概念主要有两点: 第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈...
  • Java 多线程:彻底搞懂线程池

    万次阅读 多人点赞 2019-07-09 19:27:00
    熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。 目录 1 线程池的优势 2 线程池的使用 3 线程池的工作原理 4 线程池的参数 4.1 任务队列...
  • 单核cpu多核cpu如何执行多线程

    千次阅读 2020-03-31 11:19:00
    进程: 是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程,比如电脑上的各种运行中的软件 进程和线程 进程可进一步细化为线程,是一个程序内部的一条执行路径,比如杀毒软件中的体检,杀毒,清理等...
  • TestNg多线程—— 并行执行测试

    千次阅读 2016-12-22 15:24:08
    多线程并行执行测试,可以通过参数设置来实现不同级别的多线程配置测试 1、test级别的多线程测试,每个标签下的所有方法将在...备注: 当前测试规划的执行过程中,为每个测试用例的执行使用单独的线程,最多并发2
  • 多线程中任务的执行

    千次阅读 2012-11-25 18:38:46
    多线程程序中,主要是围绕着任务的执行来展开的,所谓的任务是指一些抽象的且离散的工作单元,通过把应用程序的工作分解到多个任务中,每个任务之间有一定的事物边界,各个任务可以同时执行,从而以并发的形式来...
  • 使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待。 CountDownLatch是一个同步辅助工具,用于使一个或多个线程等待(即阻塞)知道一组在...
  • 单核多线程与多核多线程

    万次阅读 多人点赞 2018-09-29 17:20:33
    单核多线程与多核多线程 或许有些同学对于单核多线程和多核多线程有点误区,因为会听到一些同学问为什么单核能处理多线程,总结了一些...单核多线程指的是单核CPU轮流执行多个线程,通过给每个线程分配CPU时间片来实...
  • Java多线程

    万次阅读 多人点赞 2021-06-11 16:28:49
    Java多线程Java多线程线程的创建线程常见方法线程的状态线程的优先级守护线程线程组Java线程池线程池的创建线程池的参数线程池的使用线程不安全问题Java中的锁synchronized同步方法synchronized同步语句块...
  • 多线程环境下,我们可能会需要等待开辟的线程执行完后,再去执行某个方法,例如输出并行计算结果等。 但是在多线程下,线程的执行是不阻塞主线程的,这点其实也是多线程的优势,提高代码执行效率,不必相互等待...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 862,269
精华内容 344,907
关键字:

多线程的执行过程