`
wind_bell
  • 浏览: 291929 次
  • 性别: Icon_minigender_2
  • 来自: 广州
社区版块
存档分类
最新评论

多线程编程 实践篇(一)注:转

阅读更多
实战篇(一) 


在进入实战篇以前,我们简单说一下多线程编程的一般原则.

[安全性]是多线程编程的首要原则,如果两个以上的线程访问同一对象时,一个线程会损坏
另一个线程的数据,这就是违反了安全性原则,这样的程序是不能进入实际应用的.

安全性的保证可以通过设计安全的类和程序员的手工控制.如果多个线程对同一对象访问不
会危及安全性,这样的类就是线程安全的类,在JAVA中比如String类就被设计为线程安全的类.
而如果不是线程安全的类,那么就需要程序员在访问这些类的实例时手工控制它的安全性.


[可行性]是多线程编程的另一个重要原则,如果仅仅实现了安全性,程序却在某一点后不能继
续执行或者多个线程发生死锁,那么这样的程序也不能作为真正的多线程程序来应用.

相对而言安全性和可行性是相互抵触的,安全性越高的程序,可性行会越低.要综合平衡.

[高性能] 多线程的目的本来就是为了增加程序运行的性能,如果一个多线程完成的工作还不
如单线程完成得快.那就不要应用多线程了.

高性能程序主要有以下几个方面的因素:
    数据吞吐率,在一定的时间内所能完成的处理能力.
    响应速度,从发出请求到收到响应的时间.
    容量,指同时处理雅致同任务的数量.


    安全性和可行性是必要条件,如果达到不这两个原则那就不能称为真正的多线程程序.
而高性是多线程编程的目的,也可以说是充要条件.否则,为什么采用多线程编程呢?


[生产者与消费者模式]
    首先以一个生产者和消费者模式来进入实战篇的第一节.

    生产者和消费者模式中保护的是谁?
    多线程编程都在保护着某些对象,这个些对象是"紧俏资源",要被最大限度地利用,这也是
采用多线程方式的理由.在生产者消费者模式中,我们要保护的是"仓库",在我下面的这个例子中,
就是桌子(table)


    我这个例子的模式完全是生产者-消费者模式,但我换了个名字.厨师-食客模式,这个食
堂中只有1张桌子,同时最多放10个盘子,现在有4个厨师做菜,每做好一盘就往桌子上放(生产者将
产品往仓库中放),而有6个食客不停地吃(消费者消费产品,为了说明问题,他们的食量是无限的).

    一般而言,厨师200-400ms做出一盘菜,而食客要400-600ms吃完一盘.当桌子上放满了10
个盘子后,所有厨师都不能再往桌子上放,而当桌子是没有盘子时,所有的食客都只好等待.


    下面我们来设计这个程序:

    因为我们不知道具体是什么菜,所以叫它food:

    class Food{}

    然后是桌子,因为它要有序地放而且要有序地取(不能两个食客同时争取第三盘菜),所以我们
扩展LinkedList,或者你用聚合把一个LinkedList作为属性也能达到同样的目的,例子中我是用
继承,从构造方法中传入一个可以放置的最大值

    
class Table extends java.util.LinkedList{
  int maxSize;
  public Table(int maxSize){
    this.maxSize = maxSize;
  }
}

现在我们要为它加两个方法,一是厨师往上面放菜的方法,一是食客从桌子上拿菜的方法.

放菜:因为一张桌子由多个厨师放菜,所以厨师放菜的要被同步,如果桌子上已经有十盘菜了.所有厨师
就要等待:

  public synchronized void putFood(Food f){
    while(this.size() >= this.maxSize){
      try{
        this.wait();
      }catch(Exception e){}
    }
    this.add(f);
    notifyAll();
  }

拿菜:同上面,如果桌子上一盘菜也没有,所有食客都要等待:

  public synchronized Food getFood(){
    while(this.size() <= 0){
      try{
        this.wait();
      }catch(Exception e){}
    }
    Food f = (Food)this.removeFirst();
    notifyAll();
    return f;
  }

厨师类:
    由于多个厨师要往一张桌子上放菜,所以他们要操作的桌子应该是同一个对象,我们从构造
方法中将桌子对象传进去以便控制在主线程中只产生一张桌子.

厨师做菜要用一定的时候,我用在make方法中用sleep表示他要消耗和时候,用200加上200的随机数保
证时间有200-400ms中.做好后就要往桌子上放.


这里有一个非常重要的问题一定要注意,就是对什么范围同步的问题,因为产生竞争的是桌子,所以所
有putFood是同步的,而我们不能把厨师自己做菜的时间也放在同步中,因为做菜是各自做的.同样食客
吃菜的时候也不应该同步,只有从桌子中取菜的时候是竞争的,而具体吃的时候是各自在吃.
所以厨师类的代码如下:

class Chef extends Thread{
  Table t;
  Random r = new Random(12345);
  public Chef(Table t){
    this.t = t;
  }
  public void run(){
    while(true){
      Food f = make();
      t.putFood(f);
    }
  }
  private Food make(){

    try{
      Thread.sleep(200+r.nextInt(200));
    }catch(Exception e){}
    return new Food();
  }
}

同理我们产生食客类的代码如下:

class Eater extends Thread{
  Table t;
  Random r = new Random(54321);
  public Eater(Table t){
    this.t = t;
  }
  public void run(){
    while(true){
      Food f = t.getFood();
      eat(f);
    }
  }
  private void eat(Food f){
    
    try{
      Thread.sleep(400+r.nextInt(200));
    }catch(Exception e){}
  }
}


完整的程序在这儿:
package debug;
import java.util.regex.*;
import java.util.*;


class Food{}

class Table extends LinkedList{
  int maxSize;
  public Table(int maxSize){
    this.maxSize = maxSize;
  }
  public synchronized void putFood(Food f){
    while(this.size() >= this.maxSize){
      try{
        this.wait();
      }catch(Exception e){}
    }
    this.add(f);
    notifyAll();
  }
  
  public synchronized Food getFood(){
    while(this.size() <= 0){
      try{
        this.wait();
      }catch(Exception e){}
    }
    Food f = (Food)this.removeFirst();
    notifyAll();
    return f;
  }
}


class Chef extends Thread{
  Table t;
  String name;
  Random r = new Random(12345);
  public Chef(String name,Table t){
    this.t = t;
    this.name = name;
  }
  public void run(){
    while(true){
      Food f = make();
      System.out.println(name+" put a Food:"+f);
      t.putFood(f);
    }
  }
  private Food make(){
    try{
      Thread.sleep(200+r.nextInt(200));
    }catch(Exception e){}
    return new Food();
  }
}

class Eater extends Thread{
  Table t;
  String name;
  Random r = new Random(54321);
  public Eater(String name,Table t){
    this.t = t;
    this.name = name;
  }
  public void run(){
    while(true){
      Food f = t.getFood();
      System.out.println(name+" get a Food:"+f);
      eat(f);
      
    }
  }
  private void eat(Food f){
    
    try{
      Thread.sleep(400+r.nextInt(200));
    }catch(Exception e){}
  }
}

public class Test {
    public static void main(String[] args) throws Exception{
      Table t = new Table(10);
      new Chef("Chef1",t).start();
      new Chef("Chef2",t).start();
      new Chef("Chef3",t).start();
      new Chef("Chef4",t).start();
      new Eater("Eater1",t).start();
      new Eater("Eater2",t).start();
      new Eater("Eater3",t).start();
      new Eater("Eater4",t).start();
      new Eater("Eater5",t).start();
      new Eater("Eater6",t).start();

    }
}


这一个例子中,我们主要关注以下几个方面:
    1.同步方法要保护的对象,本例中是保护桌子,不能同时往上放菜或同时取菜.
    假如我们把putFood方法和getFood方法在厨师类和食客类中实现,那么我们应该如此:
(以putFood为例)

class Chef extends Thread{
  Table t;
  String name;
  public Chef(String name,Table t){
    this.t = t;
    this.name = name;
  }
  public void run(){
    while(true){
      Food f = make();
      System.out.println(name+" put a Food:"+f);
      putFood(f);
    }
  }
  private Food make(){
    Random r = new Random(200);
    try{
      Thread.sleep(200+r.nextInt());
    }catch(Exception e){}
    return new Food();
  }
  public void putFood(Food f){//方法本身不能同步,因为它同步的是this.即Chef的实例

    synchronized (t) {//要保护的是t
      while (t.size() >= t.maxSize) {
        try {
          t.wait();
        }
        catch (Exception e) {}
      }
      t.add(f);
      t.notifyAll();
    }
  }
}
    2.同步的范围,在本例中是放和取两个方法,不能把做菜和吃菜这种各自不相干的工作
放在受保护的范围中.


    3.参与者与容积比.
        对于生产者和消费者的比例,以及桌子所能放置最多菜的数量三者之间的关系
是影响性能的重要因素,如果是过多的生产者在等待,则要增加消费者或减少生产者的数据,反之
则增加生产者或减少消费者的数量.
    另外如果桌子有足够的容量可以很大程序提升性能,这种情况下可以同时提高生产者和
消费者的数量,但足够大的容时往往你要有足够大的物理内存.
分享到:
评论

相关推荐

    C#多线程编程实战完整源码

    C#多线程编程是开发高效、响应迅速的软件应用的关键技术之一,尤其在现代计算环境中,多核处理器和并发处理的需求日益增加。本资源"《C#多线程编程实战》完整源码"提供了丰富的实例,适用于学习和实践C#中的多线程...

    Linux多线程服务端编程:使用muduo+C网络库

    Linux多线程服务端编程:使用muduo+C网络库.pdf Linux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:...

    Java多线程编程实战指南(核心篇)

    Java多线程编程实战指南(核心篇) 高清pdf带目录 随着现代处理器的生产工艺从提升处理器主频频率转向多核化,即在一块芯片上集成多个处理器内核(Core),多核处理器(Multicore Processor)离我们越来越近了――如今...

    C++多线程编程实践指南:从基础到高级应用

    内容概要:本文全面介绍了C++多线程编程的技术细节和最佳实践。从基础知识讲解线程的概念及其重要性,涵盖了线程的创建与管理、线程同步机制(互斥锁与条件变量)、C++11标准线程库的使用,再到高级多线程技术如...

    Java多线程编程实战指南-核心篇

    《Java多线程编程实战指南-核心篇》是一本深入探讨Java并发编程的书籍,旨在帮助读者掌握在Java环境中创建、管理和同步线程的核心技术。Java的多线程能力是其强大之处,使得开发者能够在同一时间执行多个任务,提高...

    java 多线程编程实战指南(核心 + 设计模式 完整版)

    《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...

    多线程编程指南.pdf

    多线程编程是一种让程序能够同时执行多个任务的技术,通过在单一进程中创建多个线程来实现并发操作,从而提高了程序的效率和响应速度。这种编程方式尤其在多核处理器环境下展现出其优越性,能够充分利用硬件资源,...

    实验一 :WindowsThreads多线程编程实验

    "实验一:WindowsThreads多线程编程实验"旨在让学生深入理解和实践如何在Windows系统中创建和管理线程。通过这个实验,我们可以学习到以下几个关键知识点: 1. **线程的概念**:线程是操作系统分配CPU时间的基本...

    多线程编程指南_学习多线程编程的宝典

    1. 创建线程:使用`std::thread`构造函数传入一个可调用对象(函数、函数指针或lambda表达式)来创建新线程。 2. 同步与join:通过调用`std::thread::join()`函数等待线程结束,避免悬挂线程;`std::thread::detach...

    多线程编程基础.pdf

    ### 五、多线程编程的最佳实践 1. **最小化共享状态**:尽量减少线程间共享的数据,可以降低同步的复杂度。 2. **使用高级同步工具**:利用语言或库提供的高级同步原语,如Java的`volatile`关键字或C++的`std::...

    Linux系统下的多线程编程入门.pdf

    在Linux系统下进行多线程编程是开发高效并发应用程序的关键技术之一。本文将深入探讨Linux环境中的多线程概念、创建与管理线程的方法、线程同步与通信机制,以及多线程编程中可能遇到的问题和解决策略。 一、多线程...

    深入学习:Java多线程编程

    《深入学习:Java多线程编程》是一本专注于Java并发技术的专业书籍,旨在帮助开发者深入理解和熟练运用Java中的多线程编程。Java多线程是Java编程中的核心部分,尤其在现代高性能应用和分布式系统中不可或缺。理解并...

    c#多线程编程实战(原书第二版)源码

    《C#多线程编程实战(原书第二版)源码》是一本深入探讨C#中多线程技术的专业书籍,其源码提供了丰富的实践示例,帮助读者掌握并发编程的核心概念和技术。在C#中,多线程是实现高性能、响应式应用程序的关键组成部分...

    Windows多线程编程技术与实例(C++)(PDF)

    《Windows多线程编程技术与实例(C++)》是一本深入探讨Windows环境下多线程编程的书籍,特别适合正在学习或已经从事C++多线程开发的人员阅读。本书通过丰富的实例,详细讲解了如何在Windows操作系统中利用C++进行...

    玩转多线程编程.pptx

    * SO2MT:一个基于观察者模式的多线程编程定式,提供了线程的创建、管理和同步机制。 * MT2MO:一个基于生产者-消费者模式的多线程编程定式,提供了线程的创建、管理和同步机制。 在多线程编程中,我们需要了解多...

    c++多线程编程的十个例子

    在C++编程中,多线程技术是一种强大的工具,它允许程序同时执行多个任务,从而提高了效率和响应性。以下是对“C++多线程编程的十个例子”的详细讲解,这些例子将帮助你在Windows环境下深入理解和应用多线程。 1. **...

    Linux多线程服务端编程:使用muduo C++网络库

    本书主要讲述采用现代C++ 在x86-64 Linux 上编写多线程TCP 网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。这是在Linux 下以native 语言编写用户态高性能...

    多线程编程中英文对照.rar

    在IT领域,多线程编程是一项关键技能,尤其是在操作系统如Symbian中。多线程技术允许程序同时执行多个任务,提升系统效率和用户体验。以下是对"多线程编程"这个主题的详细解释: 1. **多线程概念**:多线程是指一个...

    linux多线程编程概述.doc

    在Linux系统中,多线程编程是一种常见的编程模式,它允许多个执行流在同一进程中并发运行,从而提高程序的效率和响应性。本篇将深入介绍Linux多线程编程的基本概念、实现方法以及注意事项。 首先,多线程是通过创建...

Global site tag (gtag.js) - Google Analytics