栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

生产者消费者模型ThreadLocal原理及实例详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

生产者消费者模型ThreadLocal原理及实例详解

1、生产者消费者模型作用和示例如下:

1)通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率 ,这是生产者消费者模型最重要的作用

2)解耦,这是生产者消费者模型附带的作用,解耦意味着生产者和消费者之间的联系少,联系越少越可以独自发展而不需要收到相互的制约

备注:对于生产者消费者模型的理解将在并发队列BlockingQueue章节进行说明,本章不做详细介绍。

package threadLearning.productCustomerModel;


//资源对象:包含商品名属性;提供生产和消费方法;
class Resource {
  private String name;//商品名
  private int count = 0;
  private boolean flag = false;//生产或者消费的控制开关
  public synchronized void set(String name) {
    // 生产资源
    while (flag) {
      try {
 // 线程等待。消费者消费资源
 wait();
      } catch (Exception e) {
      }
    }
    this.name = name + "---" + count++;
    System.out.println(Thread.currentThread().getName() + "...生产者..."
 + this.name);
    flag = true;
    // 唤醒等待中的消费者
    this.notifyAll();//唤醒在此对象监视器上等待的所有线程  Object.notifyAll()
  }

  public synchronized void out() {
    // 消费资源
    while (!flag) {
      // 线程等待,生产者生产资源
      try {
 wait();
      } catch (Exception e) {
      }
    }
    System.out.println(Thread.currentThread().getName() + "...消费者..."
 + this.name);
    flag = false;
    // 唤醒生产者,生产资源
    this.notifyAll();
  }
}

// 生产者
class Producer implements Runnable {
  private Resource res;

  Producer(Resource res) {
    this.res = res;
  }

  // 生产者生产资源
  public void run() {
    while (true) {
      res.set("商品");
    }
  }
}

// 消费者消费资源
class Consumer implements Runnable {
  private Resource res;

  Consumer(Resource res) {
    this.res = res;
  }

  public void run() {
    while (true) {
      res.out();
    }
  }
}
public class ProducerConsumerDemo {
  public static void main(String[] args) {
    Resource r = new Resource();
    Producer pro = new Producer(r);
    Consumer con = new Consumer(r);
    Thread t1 = new Thread(pro);
    Thread t2 = new Thread(con);
    t1.start();
    t2.start();
  }
}

2、ThreadLocal

  ThreadLocal提供一个线程的局部变量,访问某个线程拥有自己局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal的接口方法只有4个方法,先来了解一下:

•void set(Object value)设置当前线程的线程局部变量的值;

•public Object get()该方法返回当前线程所对应的线程局部变量;

•public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,

当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度;

•protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。

这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null;

总的来说ThreadLocal就是一种以 空间换时间 的做法,在每个Thread里面维护了一个以开地址法实现的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了。

示例1:

package threadLearning.thredLocal;
 
public class SerialNum {
  private static int nextSerialNum = 3;
  private static ThreadLocal serialNum = new ThreadLocal() {//创建一个线程本地变量
    protected synchronized Object initialValue() {
      return new Integer(nextSerialNum++);
    }
  };

  public static int get() {
    return ((Integer) (serialNum.get())).intValue();
  }
  
  public static void main(String args[]){
    Thread thead1=new Thread(new Runnable() {
      public void run() {
 System.out.println("thead1-->"+get()); 
      }
    });
    Thread thead2=new Thread(new Runnable() {
      public void run() {
 System.out.println("thead2-->"+get()); 
      }
    });
    thead1.start();
    thead2.start();
    
  }
}

运行结果:

thead1-->3
thead2-->4

示例2:

package threadLearning.thredLocal;
class Res {
  // 生成序列号共享变量
  public static Integer count = 0;
  public static ThreadLocal threadLocal = new ThreadLocal() {
    // 覆盖返回此线程局部变量的当前线程的“初始值”方法
    @Override
    protected Integer initialValue() {
      return 0;
    };
  };

  public Integer getNum() {
    int count = threadLocal.get() + 1;//get() 该方法返回当前线程所对应的线程局部变量
    threadLocal.set(count);//将此线程局部变量的当前线程副本中的值设置为指定值
    return count;
  }
}

public class ThreadLocaDemo2 extends Thread {
  private Res res;

  public ThreadLocaDemo2(Res res) {
    this.res = res;
  }

  @Override
  public void run() {
    for (int i = 0; i < 3; i++) {
      System.out.println(Thread.currentThread().getName() + "---" + "i---" + i + "--num:" + res.getNum());
    }

  }

  public static void main(String[] args) {
    Res res = new Res();
    ThreadLocaDemo2 threadLocaDemo1 = new ThreadLocaDemo2(res);
    ThreadLocaDemo2 threadLocaDemo2 = new ThreadLocaDemo2(res);
    ThreadLocaDemo2 threadLocaDemo3 = new ThreadLocaDemo2(res);
    threadLocaDemo1.start();
    threadLocaDemo2.start();
    threadLocaDemo3.start();
  }
}

运行结果:

Thread-1---i---0--num:1
Thread-2---i---0--num:1
Thread-0---i---0--num:1
Thread-2---i---1--num:2
Thread-1---i---1--num:2
Thread-2---i---2--num:3
Thread-0---i---1--num:2
Thread-1---i---2--num:3
Thread-0---i---2--num:3

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/131397.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号