`
369128396
  • 浏览: 85275 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

java多线程总结及示例(线程创建、后台线程、volatile、线程池、生产者消费者)(转)

    博客分类:
  • java
 
阅读更多
java多线程总结一:线程的两种创建方式及优劣比较

首先分析两种方式的输出结果,同样是创建了两个线程,为什么结果不一样呢?

使用实现Runnable接口方式创建线程可以共享同一个目标对象(TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。

然后再看一段来自JDK的解释:

Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参数方法。

设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread 类实现了Runnable。激活的意思是说某个线程已启动并且尚未停止。

此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。



采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。



java多线程总结二:后台线程(守护线程)
所谓的后台线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此当所有的非后台线程结束时,程序也就终止了,同时会杀死所有后台线程。反过来说,只要有任何非后台线程(用户线程)还在运行,程序就不会终止。后台线程在不执行finally子句的情况下就会终止其run方法。后台线程创建的子线程也是后台线程。

分析:从结果可以看出,十个子线程并没有无线循环的打印,而是在主线程(main())退出后,JVM强制关闭所有后台线程。而不会有任何希望出现的确认形式,如finally子句不执行。



java多线程总结五:线程池的原理及实现

1、线程池简介:
    多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   
    假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

    如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
                一个线程池包括以下四个基本组成部分:
                1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
                2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
                3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
                4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
               
    线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
    线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
    假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。


    代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了



view plaincopy to clipboardprint?package mine.util.thread; 
 
import java.util.LinkedList; 
import java.util.List; 
 
/**
* 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息
*/ 
public final class ThreadPool { 
    // 线程池中默认线程的个数为5  
    private static int worker_num = 5; 
    // 工作线程  
    private WorkThread[] workThrads; 
    // 未处理的任务  
    private static volatile int finished_task = 0; 
    // 任务队列,作为一个缓冲,List线程不安全  
    private List<Runnable> taskQueue = new LinkedList<Runnable>(); 
    private static ThreadPool threadPool; 
 
    // 创建具有默认线程个数的线程池  
    private ThreadPool() { 
        this(5); 
    } 
 
    // 创建线程池,worker_num为线程池中工作线程的个数  
    private ThreadPool(int worker_num) { 
        ThreadPool.worker_num = worker_num; 
        workThrads = new WorkThread[worker_num]; 
        for (int i = 0; i < worker_num; i++) { 
            workThrads[i] = new WorkThread(); 
            workThrads[i].start();// 开启线程池中的线程  
        } 
    } 
 
    // 单态模式,获得一个默认线程个数的线程池  
    public static ThreadPool getThreadPool() { 
        return getThreadPool(ThreadPool.worker_num); 
    } 
 
    // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数  
    // worker_num<=0创建默认的工作线程个数  
    public static ThreadPool getThreadPool(int worker_num1) { 
        if (worker_num1 <= 0) 
            worker_num1 = ThreadPool.worker_num; 
        if (threadPool == null) 
            threadPool = new ThreadPool(worker_num1); 
        return threadPool; 
    } 
 
    // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    public void execute(Runnable task) { 
        synchronized (taskQueue) { 
            taskQueue.add(task); 
            taskQueue.notify(); 
        } 
    } 
 
    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    public void execute(Runnable[] task) { 
        synchronized (taskQueue) { 
            for (Runnable t : task) 
                taskQueue.add(t); 
            taskQueue.notify(); 
        } 
    } 
 
    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    public void execute(List<Runnable> task) { 
        synchronized (taskQueue) { 
            for (Runnable t : task) 
                taskQueue.add(t); 
            taskQueue.notify(); 
        } 
    } 
 
    // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁  
    public void destroy() { 
        while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧  
            try { 
                Thread.sleep(10); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
        // 工作线程停止工作,且置为null  
        for (int i = 0; i < worker_num; i++) { 
            workThrads[i].stopWorker(); 
            workThrads[i] = null; 
        } 
        threadPool=null; 
        taskQueue.clear();// 清空任务队列  
    } 
 
    // 返回工作线程的个数  
    public int getWorkThreadNumber() { 
        return worker_num; 
    } 
 
    // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成  
    public int getFinishedTasknumber() { 
        return finished_task; 
    } 
 
    // 返回任务队列的长度,即还没处理的任务个数  
    public int getWaitTasknumber() { 
        return taskQueue.size(); 
    } 
 
    // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数  
    @Override 
    public String toString() { 
        return "WorkThread number:" + worker_num + "  finished task number:" 
                + finished_task + "  wait task number:" + getWaitTasknumber(); 
    } 
 
    /**
     * 内部类,工作线程
     */ 
    private class WorkThread extends Thread { 
        // 该工作线程是否有效,用于结束该工作线程  
        private boolean isRunning = true; 
 
        /*
         * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
         */ 
        @Override 
        public void run() { 
            Runnable r = null; 
            while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了  
                synchronized (taskQueue) { 
                    while (isRunning && taskQueue.isEmpty()) {// 队列为空  
                        try { 
                            taskQueue.wait(20); 
                        } catch (InterruptedException e) { 
                            e.printStackTrace(); 
                        } 
                    } 
                    if (!taskQueue.isEmpty()) 
                        r = taskQueue.remove(0);// 取出任务  
                } 
                if (r != null) { 
                    r.run();// 执行任务  
                } 
                finished_task++; 
                r = null; 
            } 
        } 
 
        // 停止工作,让该线程自然执行完run方法,自然结束  
        public void stopWorker() { 
            isRunning = false; 
        } 
    } 

package mine.util.thread;

import java.util.LinkedList;
import java.util.List;

/**
* 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息
*/
public final class ThreadPool {
// 线程池中默认线程的个数为5
private static int worker_num = 5;
// 工作线程
private WorkThread[] workThrads;
// 未处理的任务
private static volatile int finished_task = 0;
// 任务队列,作为一个缓冲,List线程不安全
private List<Runnable> taskQueue = new LinkedList<Runnable>();
private static ThreadPool threadPool;

// 创建具有默认线程个数的线程池
private ThreadPool() {
this(5);
}

// 创建线程池,worker_num为线程池中工作线程的个数
private ThreadPool(int worker_num) {
ThreadPool.worker_num = worker_num;
workThrads = new WorkThread[worker_num];
for (int i = 0; i < worker_num; i++) {
workThrads[i] = new WorkThread();
workThrads[i].start();// 开启线程池中的线程
}
}

// 单态模式,获得一个默认线程个数的线程池
public static ThreadPool getThreadPool() {
return getThreadPool(ThreadPool.worker_num);
}

// 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数
// worker_num<=0创建默认的工作线程个数
public static ThreadPool getThreadPool(int worker_num1) {
if (worker_num1 <= 0)
worker_num1 = ThreadPool.worker_num;
if (threadPool == null)
threadPool = new ThreadPool(worker_num1);
return threadPool;
}

// 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
public void execute(Runnable task) {
synchronized (taskQueue) {
taskQueue.add(task);
taskQueue.notify();
}
}

// 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
public void execute(Runnable[] task) {
synchronized (taskQueue) {
for (Runnable t : task)
taskQueue.add(t);
taskQueue.notify();
}
}

// 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
public void execute(List<Runnable> task) {
synchronized (taskQueue) {
for (Runnable t : task)
taskQueue.add(t);
taskQueue.notify();
}
}

// 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
public void destroy() {
while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 工作线程停止工作,且置为null
for (int i = 0; i < worker_num; i++) {
workThrads[i].stopWorker();
workThrads[i] = null;
}
threadPool=null;
taskQueue.clear();// 清空任务队列
}

// 返回工作线程的个数
public int getWorkThreadNumber() {
return worker_num;
}

// 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成
public int getFinishedTasknumber() {
return finished_task;
}

// 返回任务队列的长度,即还没处理的任务个数
public int getWaitTasknumber() {
return taskQueue.size();
}

// 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数
@Override
public String toString() {
return "WorkThread number:" + worker_num + "  finished task number:"
+ finished_task + "  wait task number:" + getWaitTasknumber();
}

/**
* 内部类,工作线程
*/
private class WorkThread extends Thread {
// 该工作线程是否有效,用于结束该工作线程
private boolean isRunning = true;

/*
* 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
*/
@Override
public void run() {
Runnable r = null;
while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了
synchronized (taskQueue) {
while (isRunning && taskQueue.isEmpty()) {// 队列为空
try {
taskQueue.wait(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!taskQueue.isEmpty())
r = taskQueue.remove(0);// 取出任务
}
if (r != null) {
r.run();// 执行任务
}
finished_task++;
r = null;
}
}

// 停止工作,让该线程自然执行完run方法,自然结束
public void stopWorker() {
isRunning = false;
}
}
}



测试代码:

view plaincopy to clipboardprint?package mine.util.thread; 
 
//测试线程池  
public class TestThreadPool { 
    public static void main(String[] args) { 
        // 创建3个线程的线程池  
        ThreadPool t = ThreadPool.getThreadPool(3); 
        t.execute(new Runnable[] { new Task(), new Task(), new Task() }); 
        t.execute(new Runnable[] { new Task(), new Task(), new Task() }); 
        System.out.println(t); 
        t.destroy();// 所有线程都执行完成才destory  
        System.out.println(t); 
    } 
 
    // 任务类  
    static class Task implements Runnable { 
        private static volatile int i = 1; 
 
        @Override 
        public void run() {// 执行任务  
            System.out.println("任务 " + (i++) + " 完成"); 
        } 
    } 

package mine.util.thread;

//测试线程池
public class TestThreadPool {
public static void main(String[] args) {
// 创建3个线程的线程池
ThreadPool t = ThreadPool.getThreadPool(3);
t.execute(new Runnable[] { new Task(), new Task(), new Task() });
t.execute(new Runnable[] { new Task(), new Task(), new Task() });
System.out.println(t);
t.destroy();// 所有线程都执行完成才destory
System.out.println(t);
}

// 任务类
static class Task implements Runnable {
private static volatile int i = 1;

@Override
public void run() {// 执行任务
System.out.println("任务 " + (i++) + " 完成");
}
}
}




运行结果:

WorkThread number:3  finished task number:0  wait task number:6
任务 1 完成
任务 2 完成
任务 3 完成
任务 4 完成
任务 5 完成
任务 6 完成
WorkThread number:3  finished task number:6  wait task number:0


分析:由于并没有任务接口,传入的可以是自定义的任何任务,所以线程池并不能准确的判断该任务是否真正的已经完成(真正完成该任务是这个任务的run方法执行完毕),只能知道该任务已经出了任务队列,正在执行或者已经完成。

2、java类库中提供的线程池简介:

     java提供的线程池更加强大,相信理解线程池的工作原理,看类库中的线程池就不会感到陌生了。


几种不同的ExecutorService线程池对象
1.newCachedThreadPool()
-缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中
-缓存型池子通常用于执行一些生存期很短的异步型任务
因此在一些面向连接的daemon型SERVER中用得不多。
-能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。
  注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止。

2. newFixedThreadPool
-newFixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程
-其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子
-和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP或UDP IDLE机制之类的),所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器
-从方法的源代码看,cache池和fixed 池调用的是同一个底层池,只不过参数不同:
fixed池线程数固定,并且是0秒IDLE(无IDLE)
cache池线程数支持0-Integer.MAX_VALUE(显然完全没考虑主机的资源承受能力),60秒IDLE 

3.ScheduledThreadPool
-调度型线程池
-这个池子里的线程可以按schedule依次delay执行,或周期执行

4.SingleThreadExecutor
-单例线程,任意时间池中只能有一个线程
-用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)

分享到:
评论

相关推荐

    JAVA 多线程的PPT和示例

    另外,java.util.concurrent包提供了高级并发工具,如BlockingQueue,它在生产者-消费者模式中非常有用,可以实现线程间的异步通信。 Java多线程的PPT和示例会详细讲解以上这些概念,并通过实例代码展示如何在实际...

    java 多线程并发实例

    - 生产者-消费者模型:这是一个经典的多线程设计模式,用于解决资源的生产与消费问题。生产者线程负责生成数据,放入缓冲区;消费者线程则负责取出数据进行处理。Java的BlockingQueue接口(如ArrayBlockingQueue)...

    Java多线程管理示例

    下面我们将深入探讨Java多线程的核心概念、同步机制、死锁问题以及wait/notify机制,以"生产者与消费者"的例子来具体阐述。 首先,了解Java中的线程。线程是操作系统分配CPU时间的基本单位,每个线程都有自己的程序...

    java线程安全以及生产者消费者demo

    Java线程安全与生产者消费者模型是多线程编程中的两个重要概念,它们在并发处理中扮演着关键角色。在Java中,线程安全是指一个类或者方法在多线程环境下能够正确地处理数据,避免数据的不一致性或竞态条件。而生产者...

    详细剖析JAVA多线程案例教学

    生产者消费者模式是一种经典的多线程编程模型,用于解决多线程之间的数据传递问题。在这个模式中,生产者负责生成数据,消费者负责消费数据。Java中可以通过队列、锁等工具来实现这一模式。 - **示例代码**: ```...

    java多线程并发实战和源码

    通过阅读这些示例,可以深入理解并发设计模式,如生产者-消费者模型、双端队列、线程池的实现原理等。 总结来说,Java多线程并发实战和源码的学习涵盖了线程创建与管理、同步机制、并发容器、内存模型以及并发工具...

    JAVA多线程模式高清版+DEMO

    这个压缩包文件"JAVA多线程模式高清版+DEMO"显然是关于Java多线程设计模式的详细教程,很可能包含了理论讲解、代码示例以及实战DEMO。 在Java多线程编程中,了解和掌握以下知识点至关重要: 1. **线程的创建与启动...

    java多线程编程实例_Source

    在生产者消费者模型或其他同步问题中,这些方法起到关键作用。 3. 线程状态:线程有新建、就绪、运行、阻塞和终止五种状态。实例可能涉及线程的启动、暂停、恢复和停止操作。 三、线程池 Java的ExecutorService和...

    java多线程设计模式详解(PDF及源码)

    1. 生产者消费者模式:这种模式用于处理生产数据和消费数据的场景,通过阻塞队列实现线程间的同步和通信,如Java的BlockingQueue接口。 2. 管道模式(Pipeline):将一系列操作链接在一起,每个操作在一个单独的...

    smoker_java多线程_

    标题"smoker_java多线程_"暗示我们将探讨的是一个关于Java多线程的示例,可能是解决某个特定的并发问题。描述中提到的"实现经典多线程问题中的多线程问题"进一步说明我们将深入研究一些常见的多线程挑战,例如死锁、...

    JAVA线程学习(源代码)

    另外,`java.util.concurrent`包中的BlockingQueue是一个高效的线程间通信工具,它提供了插入和移除元素的阻塞操作,常用于生产者-消费者模式。 异常处理在多线程编程中也至关重要。如果一个线程在运行过程中抛出未...

    Java 多线程学习详细总结

    【Java 多线程学习详细总结】 在Java编程中,多线程是处理并发执行任务的关键技术。本文将深入探讨Java中的多线程概念、实现方式、线程状态转换、线程调度、线程同步以及数据传递等相关知识。 1. **扩展`java.lang...

    java多线程基础学习文档

    此外,还有BlockingQueue阻塞队列,它可以作为线程间的缓冲区,实现生产者消费者模式。条件变量(如Semaphore、CountDownLatch、CyclicBarrier)也是线程间同步和通信的重要工具。 6. 死锁: 死锁是多线程编程中...

    Java多线程演示系统.zip

    这个"Java多线程演示系统.zip"很可能包含了一个示例项目或教程,用于展示如何在Java中设计和管理多线程。 在Java中,多线程可以通过两种主要方式实现:继承Thread类和实现Runnable接口。继承Thread类直接创建一个新...

    java多线程设计模式

    Java多线程设计模式是Java开发中不可或缺的一部分,它涉及到并发编程、系统性能优化以及程序的可扩展性。在多核处理器环境下,合理利用多线程可以极大地提高应用程序的执行效率。本文将深入探讨Java中的一些重要多...

    Java多线程

    下面是一个实现`Runnable`接口的多线程示例: ```java class MyRunnable implements Runnable { public void run() { // 线程执行的代码 } } public class Main { public static void main(String[] args) { ...

    Java线程间通信的代码示例.zip

    Java线程间通信是多线程编程中的一个重要概念,它涉及到如何在并发执行的线程之间有效地传递信息和协调工作。在Java中,线程间通信主要通过共享内存(如共享变量)和消息传递(如wait(), notify(), notifyAll()等...

    深入Java多线程和并发编程

    - **阻塞队列(BlockingQueue)**:提供了一种线程安全的方式来处理生产者-消费者模式中的数据交换。 - **可重入锁(ReentrantLock)**:提供了比内置锁更灵活的锁定机制,支持公平性和非公平性锁定策略。 - **同步...

    东半球最好的多线程讲义

    3. **线程通信**:讲述如何使用生产者消费者模型、信号量、条件变量等机制进行线程间的通信。 4. **线程池**:Java中的ExecutorService和ThreadPoolExecutor,以及它们如何帮助管理线程的创建和销毁,提高系统性能...

    java多线程编程起步

    在Java编程领域,多线程是一项至关...总结:Java多线程编程是理解和掌握并发编程的关键,它涉及到线程的创建、管理、同步和通信等多个方面。通过实践和学习,你可以编写出高效、安全的多线程程序,应对复杂的并发场景。

Global site tag (gtag.js) - Google Analytics