本文讲述Java中的线程同步和生产者消费者问题,其中主要涉及线程同步和wait()、notify()方法的用法。

wait和notify方法只能用在线程同步中,wait和notify是object的方法,因此任何对象都能调用,当一个线程中调用wait方法时会将该线程阻塞,将cpu资源让给其他线程,关键的一点是在线程阻塞前会将持有的锁释放,这一点是和sleep方法的很大区别,sleep方法使线程睡眠的话是不会主动释放锁的,直到sleep时间到或被中断线程唤醒。wait方法将持有的锁释放然后阻塞调用该wait方法的线程,直到设置的wait时间耗尽或者被notify唤醒重新持有锁,调用wait的线程被阻塞后,CPU执行其他线程,在其他线程中调用了notify或notifyAll后会唤醒被阻塞的线程。

生产者消费者问题中,有一个先后问题,必须先生产再消费,要吃饭必须先种出稻谷,生产者和消费者问题和Linux的应用编程中的竞争互斥问题是一样的。生产为一个线程,消费为一个线程,有一个仓库存放产品,生产出的产品放在仓库中,要消费也要去仓库中取产品,所以生产线程和消费线程是共同持有仓库这个锁的。当生产者持有锁的时候不能消费,在消费线程持有锁的时候不能生产。当仓库满了以后还意图继续生产则调用wait将生产线程阻塞,释放锁,将CPU让给消费线程,消费线程消费了产品以后仓库不再是满的状态,然后消费线程调用notify唤醒生产线程可以继续生产,当消费线程执行完以后释放锁,生产线程唤醒了重新获得了刚被消费线程释放的锁,然后生产线程就可以继续执行了;(^_^)当消费线程将仓库中的产品消费完后,消费线程意图再次消费却发现仓库空了不能消费,所以调用wait释放锁将自己阻塞,生产线程获得cpu执行权和锁去生产产品,生产了产品以后放到仓库调用notify唤醒消费线程,告诉消费线程仓库有东东了,你可以去消费了,当然是要等生产线程执行完释放锁以后消费线程才有机会重新获得锁并去消费。

import java.util.*;
public class lesson911 {
public static void main(String [] args) {
StoreHouse sh = new StoreHouse();
Producer p =new Producer(sh); //创建生产者线程
Consumer c = new Consumer(sh); //创建消费线程
new Thread(p).start(); //启动线程
new Thread(c).start(); //无论哪个线程先启动都必须是先生产再消费 }
} class Product { //产品
int id;
Product(int id) {
this.id = id;
}
public String toString() { //重新定义toString方法,其实这个程序中不需要,没用到。
return "product:"+id;
} }
class StoreHouse { //定义仓库
Product [] ArrProduct = new Product[6]; //仓库只能容纳6个产品
int index=0;
int num_push=0,num_pop=0;
public synchronized void push(Product product) { //生产:将产品放到仓库
while(index==ArrProduct.length) {
try {
System.out.println("$$仓库满了$$(^_^)");
this.wait(); //当仓库满了以后调用wait,阻塞意图再次生产的线程。 }catch(InterruptedException e) {
e.printStackTrace();
}
}
this.notify(); //正常生产,调用notify通知消费线程仓库已有产品可去仓库消费
//System.out.println("notify 消费者");
ArrProduct[index] = product;
index++;
num_push++;
System.out.println("####生产了产品###:"+(num_push-1));
}
public synchronized Product pop() { //消费:将产品从仓库取出
while(index==0) {
try {
System.out.println("&&仓库空了&&(@_@)");
this.wait(); //当仓库空了以后,调用wait阻塞意图再次消费的消费线程
}catch(InterruptedException e) {
e.printStackTrace();
}
}
this.notify(); //正常消费,调用notify告诉生产线程现在仓库已经有空位可以继续生产
// System.out.println("notify 生产者");
index--;
num_pop++;
System.out.println("*******消费了产品*******:"+(num_pop-1));
return ArrProduct[index];
} }
class Producer implements Runnable { //生产者线程
StoreHouse sh = null;
Producer(StoreHouse sh) { //生产线程和消费线程都是操作的同一个仓库。
this.sh = sh;
} public void run() { for(int i=0;i<15;i++) {
Product product = new Product(i);
sh.push(product); //往仓库中添加产品 try {
Thread.sleep((int)(Math.random()*1000));
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
} class Consumer implements Runnable { //消费者线程
StoreHouse sh = null;
Consumer(StoreHouse sh) {
this.sh = sh;
} public void run() { for(int i=0;i<15;i++) {
Product product = sh.pop(); try {
Thread.sleep((int)(Math.random()*1000));
}catch(InterruptedException e) {
e.printStackTrace();
} }
}
}

运行结果如下图所示




初识Java--线程同步(2)的更多相关文章

  1. java 线程同步 原理 sleep和wait区别

    java线程同步的原理java会为每个Object对象分配一个monitor, 当某个对象(实例)的同步方法(synchronized methods)被多个线程调用时,该对象的monitor将负责处 ...

  2. Java线程同步_1

    Java线程同步_1 synchronized 该同步机制的的核心是同步监视器,任何对象都可以作为同步监视器,代码执行结束,或者程序调用了同步监视器的wait方法会导致释放同步监视器 synchron ...

  3. Java线程同步之一--AQS

    Java线程同步之一--AQS 线程同步是指两个并发执行的线程在同一时间不同时执行某一部分的程序.同步问题在生活中也很常见,就比如在麦当劳点餐,假设只有一个服务员能够提供点餐服务.每个服务员在同一时刻 ...

  4. java线程 同步临界区:thinking in java4 21.3.5

    java线程 同步临界区:thinking in java4 21.3.5 thinking in java 4免费下载:http://download.csdn.net/detail/liangru ...

  5. JAVA - 线程同步和线程调度的相关方法

    JAVA - 线程同步和线程调度的相关方法 wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁:wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等 ...

  6. Java线程同步的四种方式详解(建议收藏)

    ​ Java线程同步属于Java多线程与并发编程的核心点,需要重点掌握,下面我就来详解Java线程同步的4种主要的实现方式@mikechen 目录 什么是线程同步 线程同步的几种方式 1.使用sync ...

  7. Java线程同步和线程通信

    一.线程同步 当多个线程访问同一个数据时,非常容易出现线程安全问题.这时候就需要用线程同步. 不可变类总是线程安全的,因为它的对象状态是不可改变的,但可变类对象需要额外的方法来保证线程安全. 1.同步 ...

  8. 【总结】Java线程同步机制深刻阐述

    原文:http://hxraid.iteye.com/blog/667437 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread ...

  9. Java线程同步的方式

     java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),      将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的 ...

  10. Java线程同步(synchronized)——卖票问题

    卖票问题通常被用来举例说明线程同步问题,在Java中,采用关键字synchronized关键字来解决线程同步的问题. Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1, ...

随机推荐

  1. shell基础——二元比较操作符

    二元比较操作符,比较变量或者比较数字.注意数字与字符串的区别. 整数比较 -eq 等于,如:if [ "$a" -eq "$b" ]-ne 不等于,如:if [ ...

  2. HeadFirst设计模式读书笔记(2)-观察者模式(Observer Pattern)

    观察者模式:定义了对象之间一对多的依赖关系,这样一来,当一个对象的状态发生改变时,它的依赖者将会受到通知并且自动更新. 有一个模式可以帮你的对象知悉现况,不会错过该对象感兴趣的事,对象甚至在运行时可以 ...

  3. USB mass storage协议

    这一节主要把在实现“linux模拟U盘功能”过程中的一些调试过程记录下来,并加以解析. 一.背景知识     1.USB Mass Storage类规范概述        USB 组织在univers ...

  4. 处理编译错误"0" is an invalid value for the "DebugInformation" parameter of the "DCC"

    在编译“MustangpeakCommonLib-master.zip”时,遇到了这个问题.网上搜了一下: 处理编译错误"0" is an invalid value for the "DebugIn ...

  5. ARM和X86功耗差别的深层原因探讨

    ARM和X86功耗差别的深层原因探讨 ARM和X86功耗的差别一直是个很热的话题.ARM可以做的很低,甚至1瓦都不到.而X86服务器的芯片可以达到100-200瓦,就算是嵌入式处理器Atom系列也需要 ...

  6. Linux下安装nfs服务器

    1. 安装nfs服务 $sudo apt-get install nfs-kernel-server portmap 2. 在配置文件/etc/exports中添加以下内容/home/jxhui/nf ...

  7. c语言_常见图片格式判断

    c语言_常见图片格式判断 我想尽各种思路.今天,终于把图片判断搞定了. 在此,我写一下我的思路.希望对那些不想看代码的朋友们有帮助. 常风的的图片格式有:bmp,png,jpg,gif等图片格式. 我 ...

  8. DB操作用法总结。

    用到了慢慢总结.用到了随时更新. 其实可以看手册了.但是看了完了手册之后,还是记不住. 1. mysql select * from table where id in(1,2,3,3,4) 怎么能显 ...

  9. 无组件客户端js图片压缩

    <div class="free-upload"> <p>上传您的约会照片,一张合影.一张票据哦!</p> <div class=&quo ...

  10. 浅析C# 中object sender与EventArgs e (转)

    一.了解C#中的预定义事件处理机制    在写代码前我们先来熟悉.net框架中和事件有关的类和委托,了解C#中预定义事件的处理. EventArgs是包含事件数据的类的基类,用于传递事件的细节. Ev ...