Java多线程小结

JAVA实现多线程的方式有两种,继承Thread,实现Runnable,

  但在JDK1.5之后又有一种新的方式:实现Callable<V>接口

package Test2016.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Demo9 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        ExecutorService executors = Executors.newFixedThreadPool(5);

        long start = System.currentTimeMillis();

        /**
        List<Future<Integer>> futures = new ArrayList<Future<Integer>>(10);

        for (int i = 1; i <= 10; i++) {
            futures.add(executors.submit(new MyTask1(i)));
        }

        for (Future<Integer> future : futures) {
            Integer result = future.get();

            System.out.println("线程:" + result + "执行完毕!!!");
        }
        */

        CompletionService<Integer> completionServices = new ExecutorCompletionService<Integer>(executors);

        for (int i = 1; i <= 10; i++) {
            completionServices.submit(new MyTask1(i));
        }

        for (int i = 1; i <= 10; i++) {
            Integer result = completionServices.take().get();

            System.out.println("线程:" + result + "执行完毕!!!");
        }

        long end = System.currentTimeMillis();

        System.out.println("本次共历时:" + (end - start) / 1000 + "秒");

        executors.shutdown();  //必须手动关闭线程池
    }
}

class MyTask1 implements Callable<Integer> {

    private int taskNum;

    public MyTask1(int num) {
        this.taskNum = num;
    }

    @Override
    public Integer call() throws Exception {

        System.out.println("执行线程:" + taskNum);
        Thread.sleep(1000);
        return taskNum;
    }

}

执行结果:

Future:                

CompletionService:

使用Future接口获取任务的状态,按照的是线程的执行顺序来返回结果,即:先执行先获取结果

使用CompletionService接口来获取任务的状态,按照的是执行结束的顺序获取对应的结果,即:先结束先获取结果

  EG:如果两个线程,线程1先执行,线程2后执行,但是线程1执行完需要100s,线程2执行完需要1s,

    如果使用Future获取结果状态:

      线程1 complete!!!

      线程2 complete!!!

    如果使用CompletionService获取结果状态:

      线程2 complete!!!

      线程1 complete!!!

附:ExecutorService接口(源码:public interface ExecutorService extends Executor{  })创建线程池方式:

  


ThreadPoolExecutor实现线程池  ThreadPoolExecutor类是ExecutorService接口的一个实现类     源码:public class ThreadPoolExecutor extends AbstractExecutorService { }        public abstract class AbstractExecutorService implements ExecutorService { }
package Test2016.demo;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo8 {

    public static void main(String[] args) {

        /**
         * corePoolSize : 线程池维护线程的最少数量
         * maximumPoolSize : 线程池维护线程的最大数量
         * keepAliveTime : 线程池维护线程所允许的空闲时间
         * unit : 线程池维护线程所允许的空闲时间的单位
         * workQueue : 线程池所使用的缓冲队列
         * handler : 线程池对拒绝任务的处理策略
         * */
        ThreadPoolExecutor executor = new ThreadPoolExecutor(15, 50, 200, TimeUnit.NANOSECONDS, new ArrayBlockingQueue<Runnable>(15));

        for (int i = 1; i <= 50; i++) {
            MyTask myTask = new MyTask(i);

            executor.execute(myTask);

             System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
                     executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
    }
}

class MyTask implements Runnable {

    private int taskNum;

    public MyTask(int num) {
        this.taskNum = num;
    }

    @SuppressWarnings("static-access")
    public void run() {
        System.out.println("正在执行task:" + taskNum);

        try {
            Thread.currentThread().sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task "+taskNum+"执行完毕");
    }

}

1、corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。

  在创建了线程池后,默认情况下,线程池中并没有任何线 程,而是等待有任务到来才创建线程去执行任务,

  除非调用了prestartAllCoreThreads()或者 prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,

  即在没有任务到来之前就创建 corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,

  就会创建一个线程去执行任务,当线 程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

2、maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;

3、keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。

  默认情况下,只有当线程池中的线程数大于corePoolSize 时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,

  即当线程池中的线程数大于corePoolSize 时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。

  但是如果调用了 allowCoreThreadTimeOut(boolean)方法,

  在线程池中的线程数不大于corePoolSize 时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

4、unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

5、workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,

          一般来说,这里的阻塞队列有以下几种选择:

ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;

  ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。

    线程池的排队策略与BlockingQueue有关。

6、threadFactory:线程工厂,主要用来创建线程;

7、handler:表示当拒绝处理任务时的策略,有以下四种取值:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

参考博文:http://www.cnblogs.com/dolphin0520/p/3932921.html

时间: 2024-10-12 04:09:11

Java多线程小结的相关文章

java多线程小结,及解决应用挂死的问题

这两天为了定位JBOSS老是挂死的问题,学习了一下JAVA多线程方面的知识,在此总结一下 1.在Java程序中,JVM负责线程的调度.线程调度是指按照特定的机制为多个线程分配CPU的使用权. 调度的模式有两种:分时调度和抢占式调度.分时调度是所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间:抢占式调度是根据线程的优先级别来获取CPU的使用权.JVM的线程调度模式采用了抢占式模式. 2.Thread类实际上也是实现了Runnable接口的类. 在启动的多线程的时候,需要先通过Thr

【Java基础】Java多线程小结

在说多线程之前,首先要清楚为啥要提出多线程,这就要明白线程和进程间的区别了. 线程和进程间的区别 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 一个线程可以创建和撤销另一个线程,同一个进程中

黑马程序员___多线程小结

----------- android培训.java培训.java学习型技术博客.期待与您交流! --------- 进程和线程 进程是正在进行中的程序,指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程. Java程序的进程里有几个线程:主线程, 垃圾回收线程(后台线程) 线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据.多线程:在同一个进程中同时运行的多个任务;一个进程至少有一个线程,为了提高效率,可以在一个进程中

Java多线程---同步与锁

一,线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 二.同步和锁定 1.锁的原理 Java中每个对象都有一个内置锁. 当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁定对象.在对象上锁定或在对象上同步. 当程序运行到synchronized同步方法或代码块时该对象锁才起作用. 一个对象只有一个锁.所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回

java多线程并发概览

一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. "同时"执行是人的感觉,在线程之间实际上轮换执行. 二.Java中的线程 在J

【Java多线程】两种基本实现框架

Java多线程学习1——两种基本实现框架 一.前言 当一个Java程序启动的时候,一个线程就立刻启动,改程序通常也被我们称作程序的主线程.其他所有的子线程都是由主线程产生的.主线程是程序开始就执行的,并且程序最终是以主线程的结束而结束的. Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的.每用Java命令启动一个Java应用程序,就会启动一个JVM进程.在同一个JVM进程中,有且只有一个进程,就是它自己.在这个JVM环境中,所有程序代码的运行都

java多线程之线程的同步与锁定(转)

一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. publicclass Foo { privateint x = 100; publicint getX() { return x;     } publicint fix(int y) {         x = x - y; return x;     } } publicclass MyRunnable i

Java之十三 Java多线程

你一定知道多任务处理,因为它实际上被所有的现代操作系统所支持.然而,多任务处理有两种截然不同的类型:基于进程的和基于线程的.认识两者的不同是十分重要的.对很多读者,基于进程的多任务处理是更熟悉的形式.进程(process)本质上是一个执行的程序.因此,基于进程(process-based)的多任务处理的特点是允许你的计算机同时运行两个或更多的程序.举例来说,基于进程的多任务处理使你在运用文本编辑器的时候可以同时运行Java编译器.在基于进程的多任务处理中,程序是调度程序所分派的最小代码单位.在基

Java并发指南1:并发基础与Java多线程

什么是并发 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片运行. 随着多任务对软件开发者带来的新挑战,程序不在能假设独占所有的CPU时间.所有的内存和其他计算机资源.一个好的程序榜样是在其不再使用这些资源时对其进行释放,以使得其他程序能有机会使用这些资源. 再后来发