`
flyPig
  • 浏览: 140519 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

多线程常用模式总结二

    博客分类:
  • Java
阅读更多
6.Thread-Per-Message模式
这个模式在swing开发中随处可见。比如我们希望点击一个按钮就启动文件系统扫描程序,一般的做法就是
okButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				new Thread(new Runnable(){
                            public void run() {
				doFileSystemScan();
			}}).start();
			}});

简单的理解就是来一个请求,开启一个线程去处理请求。这样的应用场景也见于Servlet容器处理http请求,socket处理文件读写操作等。这个设计主要是用来解决一些耗时的操作,提高响应性,但是同时也会产生额外的线程的启动开销和无法得到响应结果。创建和销毁线程本身就有一定的开销,如果频繁创建和销毁线程,CPU和内存开销就不可忽略,垃圾收集器还必须负担更多的工作。为解决线程开销的问题,有了worker线程模式;为解决响应结果的问题,有了Future模式。

7.Worker线程模式
先初始化一个线程池,所有线程处于阻塞状态。接受到一个新的请求后,就从线程池中挑选一个等待的线程并执行请求处理。处理完毕后,线程并不结束,而是转为阻塞状态再次被放入线程池中,这样就避免了频繁创建和销毁线程。以一个简单的例子。
首先是请求类Request
public class Request {
    private final String name;
    private final int number;  
    private static final Random random = new Random();
    public Request(String name, int number) {
        this.name = name;
        this.number = number;
    }
    public void execute() {
        System.out.println(Thread.currentThread().getName() + " executes " + this);
        try {
            Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException ignore) {
        }
    }
    public String toString() {
        return "[ Request from " + name + " No." + number + " ]";
    }
}

再是请求处理器,它会接收所有请求,队列缓冲起来,交给workerThread执行。
public class RequestProcesser {
    private static final int MAX_REQUEST = 100;
    private final Request[] requestQueue;
    private int tail;
    private int head;
    private int count; // Request的数量

    private final WorkerThread[] threadPool;

    public RequestProcesser(int threads) {
        this.requestQueue = new Request[MAX_REQUEST];
        this.head = 0;
        this.tail = 0;
        this.count = 0;

        threadPool = new WorkerThread[threads];
        for (int i = 0; i < threadPool.length; i++) {
            threadPool[i] = new WorkerThread("Worker-" + i, this);
        }
    }
    
    /**
     * 启动所有工作线程
     */
    public void startWorkers() {
        for (int i = 0; i < threadPool.length; i++) {
            threadPool[i].start();
        }
    }
    
    /**
     * 放入请求到工作队列
     * @param request
     */
    public synchronized void putRequest(Request request) {
        while (count >= requestQueue.length) {
            try {
                wait();
            } catch (InterruptedException ignore) {
            }
        }
        requestQueue[tail] = request;
        tail = (tail + 1) % requestQueue.length;
        count++;
        notifyAll();
    }
    
    /**
     * 得到最近的请求
     * @return
     */
    public synchronized Request takeRequest() {
        while (count <= 0) {
            try {
                wait();
            } catch (InterruptedException ignore) {
            }
        }
        Request request = requestQueue[head];
        head = (head + 1) % requestQueue.length;
        count--;
        notifyAll();
        return request;
    }
}

接下来是真正的workerThread.
public class WorkerThread extends Thread {
    private final RequestProcesser queue;
    public WorkerThread(String name, RequestProcesser queue) {
        super(name);
        this.queue = queue;
    }
    public void run() {
        while (true) {
            Request request = queue.takeRequest();
            request.execute();
        }
    }
}

下面是模拟并发请求的clientThread
public class ClientThread extends Thread {
    private final RequestProcesser processer;
    private static final Random random = new Random();
    public ClientThread(String name, RequestProcesser processer) {
        super(name);
        this.processer = processer;
    }
    public void run() {
        try {
            for (int i = 0; true; i++) {
                Request request = new Request(getName(), i);
                processer.putRequest(request);
                Thread.sleep(random.nextInt(1000));
            }
        } catch (InterruptedException e) {
        }
    }
}
最后用个main类来跑下这个小程序。
public class Main {
    public static void main(String[] args) {
        RequestProcesser processer = new RequestProcesser(5);
        processer.startWorkers();
        new ClientThread("hankzhang", processer).start();
        new ClientThread("yashironan", processer).start();
        new ClientThread("yunyunzei", processer).start();
    }
}

在这个小程序里面,当队列满,采用的方式是client线程阻塞。对于一般的web服务器在用户请求繁忙时就会拒绝用户:HTTP 503 SERVICE UNAVAILABLE。

8.Future模式
Thread-Per-Message模式引申出2个问题,worker Thread解决了一个,Future就是用来解决另一个的。我个人理解就是,在请求发出后,马上可以获取返回值Future,但是这个返回值Future并不是真正的值,因为线程还在跑呢,跑完之前不会有结果出来的。Future中有个getContent方法就是获取真正的返回值的,但是这个方法是阻塞性的,结果返回之前是不会跳出来的。
首先是Future接口。
public interface Future {
    public abstract String getContent();
}

然后是它的实现类。
public class FutureTask implements Future {
    private RealData realdata = null;
    private boolean ready = false;
    public synchronized void setRealData(RealData 
realdata) {
        if (ready) {                        
            return;
        }
        this.realdata = realdata;
        this.ready = true;
        notifyAll();
    }
    public synchronized String getContent() {
        while (!ready) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        return realdata.getContent();
    }
}

再是真实的返回数据类。
public class RealData implements Future {
    private final String content;
    public RealData(int count, char c) {
        System.out.println(" making RealData(" + count + ", " + c + ") BEGIN");
        char[] buffer = new char[count];
        for (int i = 0; i < count; i++) {
            buffer[i] = c;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
        System.out.println(" making RealData(" + count + ", " + c + ") END");
        this.content = new String(buffer);
    }
    public String getContent() {
        return content;
    }
}

用以模拟请求处理的Host。
public class Host {
    public Future request(final int count, final char c) {
        System.out.println(" request(" + count + ", " + c + ") BEGIN");
        //建立FutureData
        final FutureTask future = new FutureTask();
        //建立RealData,启动新线程
        new Thread() {                                      
            public void run() {                             
                RealData realdata = new RealData(count, c);
                future.setRealData(realdata);
            }                                               
        }.start();                                          
        System.out.println(" request(" + count + ", " + c + ") END");
        //取回FutureData,作为传回值
        return future;
    }
}

用个Main程序跑起来
public class Main {
    public static void main(String[] args) {
        System.out.println("main BEGIN");
        Host host = new Host();
        Future data1 = host.request(10, 'A');
        Future data2 = host.request(20, 'B');
        Future data3 = host.request(30, 'C');

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }

        System.out.println("data1 = " + data1.getContent());
        System.out.println("data2 = " + data2.getContent());
        System.out.println("data3 = " + data3.getContent());
        System.out.println("main END");
    }
}

jdk1.5后,有了真正的Future接口以及它的实现类FutureTask,实现的更为精巧,详细。
分享到:
评论

相关推荐

    多线程单例模式并发访问

    总结起来,多线程环境下的单例模式实现需要注意线程安全问题,尤其是懒汉式单例,需要采取适当的同步措施来防止多线程环境下的实例化问题。此外,对于不同场景的需求,可以选择不同的实现方式来优化性能和资源使用。

    多线程基础总结.xmind

    多线程基础理论, 多线程中常用API,多线程的实现方式, 线程池以及创建线程池相关API, 常见的设计模式等内容

    JAVA多线程设计模式详解

    1. 单例模式:在多线程环境中保证单例对象的唯一性,常用双检锁/双重校验锁定(DCL)和静态内部类等方式实现。 2. 生产者-消费者模式:通过阻塞队列实现生产者线程和消费者线程之间的数据交换,利用BlockingQueue...

    Java 多线程 设计模式

    以上只是Java多线程设计模式的一些基本概念和常用技术,实际开发中还需要根据具体需求灵活运用,结合设计模式来解决问题。《Java 多线程设计模式》一书的源代码应该涵盖了这些知识点的具体实现,通过阅读和实践,...

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

    设计模式则是解决软件开发中常见问题的经验总结,它为多线程环境下的编程提供了有效的解决方案。本资源包括了详细的“Java多线程设计模式详解”PDF文档以及配套的源码,帮助开发者深入理解和应用这些模式。 首先,...

    Java多线程-多线程知识点总结和企业真题

    ### Java多线程知识点总结及企业真题解析 #### 一、知识点总结 ##### (1)多线程相关概念 1. **程序、进程和线程的区分**: - **程序**:为了完成特定的任务而编写的指令集合。它是静态的概念。 - **进程**:...

    java中常用设计模式总结心得

    以下是对Java中常用设计模式的详细解释: 1. **单例模式**:单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于配置管理、线程池或者数据库连接池等场景。实现方式有懒汉式(线程不安全)、...

    多核多线程下java设计模式性能提升.pdf

    总结来说,本文档通过介绍单例模式在多核多线程环境下的性能提升方法,探讨了Java设计模式在现代大型系统应用中的优化策略,并对JDK未来的设计模式实现提出期望,为Java开发人员提供了宝贵的技术指导和参考。

    多线程服务器的几种常用模型

    ### 多线程服务器的几种常用模型 #### 1. 进程与线程 在计算机科学中,**进程**和**线程**是两个重要的概念。进程是资源分配的基本单位,而线程则是调度的基本单位。每个进程都有自己的独立地址空间,这意味着不同...

    Java多线程编程环境中单例模式的实现

    ### Java多线程编程环境中单例模式的实现 #### 概述 单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,并提供一个全局访问点。在Java中,单例模式的应用非常广泛,特别是在资源管理、日志记录、...

    Java 多线程学习总结6

    在“Java多线程学习总结6”这个主题中,我们可以深入探讨Java多线程的实现、管理及优化。下面将详细阐述相关知识点。 1. **线程的创建方式** - **继承Thread类**:自定义类继承Thread类,并重写run()方法,创建...

    多线程编程指南

    提供了一个包含多线程编程中常用术语的词汇表,方便读者查阅。 #### 结束语 本指南详细介绍了多线程编程在iOS开发中的应用,希望读者能够从中受益,并在实际项目中有效地运用多线程技术。 #### 推荐资源 最后,...

    ios 多线程编程指南

    对于一些常用的框架,如Foundation Framework、ApplicationKit和CoreData,Apple提供了线程安全的总结,指导开发者如何在这些框架内安全地使用多线程。 以上就是iOS多线程编程指南的主要知识点,详细解读了多线程...

    C# 多线程教材

    ### C#多线程教材知识点详解 ...以上是对C#多线程教材的详细知识点总结,涵盖了从基本概念到高级主题的相关内容。掌握这些知识将有助于开发者更好地利用多线程技术,构建高效、可靠的多线程应用程序。

    java 多线程单例模式详解

    ### Java多线程单例模式详解 #### 一、单例模式概述 单例模式(Singleton Pattern)是一种常用的软件设计模式,它确保一个类仅有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁实例化然后销毁的...

    多线程,多接收模式串口类LsComm

    总结,LsComm是串口通信领域的强大工具,通过多线程和多接收模式,它为开发者提供了高效、灵活的解决方案。无论是在传统的VC6环境中还是更新的VC7环境下,LsComm都能发挥出色的表现,简化串口通信的实现,提高软件的...

    支持多线程AC自动机

    总结来说,支持多线程AC自动机的Snort改进版是一种高效的方法,它结合了AC自动机的快速搜索能力和多线程的并发处理能力,旨在提高网络入侵检测系统的性能和响应速度,对于应对现代网络安全挑战具有重要意义。

    Java多线程技术

    在多线程编程中,常用的设计模式有生产者-消费者模式、读写锁模式等。 10. 多线程工具类:Java提供了诸如Timer、ScheduledExecutorService等工具类,它们能够帮助开发者更方便地进行时间安排、任务调度等操作。 ...

    多线程编程指南PDF

    ### 多线程编程指南知识点总结 #### 一、多线程基础介绍 - **定义多线程术语**: - **线程**:线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 - **多线程**:指的是...

    几种常用的设计模式介绍总结

    单例模式是一种常用的创建型设计模式,它保证一个类仅有一个实例,并提供一个全局访问点。单例模式通常用于控制资源的共享访问,例如数据库连接池、日志管理器等。 #### 实现方式 - **构造函数私有化**:防止外部...

Global site tag (gtag.js) - Google Analytics