本文讲述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. GDAL库——读取图像并提取基本信息

    GDAL库是一个跨平台的栅格地理数据格式库,包括读取.写入.转换.处理各种栅格数据格式(有些特定的格式对一些操作如写入等不支持).它使用了一个单一的抽象数据模型就支持了大多数的栅格数据.这里有GDAL ...

  2. C++之单元测试

    以前编写程序从没有做过单元测试的工作,所以在后期会花很多时间去纠错,这也就是软件工程中的2:8定律.最近要完成一个项目,要求要对系统中的主类和主函数作出单元测试的保证,才去查找了相关方面的资料,看过后 ...

  3. poj 1887 Testing the CATCHER_最长上升子序列

    题意:题目太长没看,直接看输入输出猜出是最长下降子序列 用了以前的代码直接a了,做法类似贪心,把最小的顺序数存在数组里面,每次二分更新数组得出最长上升子序列 #include<iostream& ...

  4. iOS伪实现打地鼠游戏

    打地鼠是一款可以用iOS知识来实现的一种游戏.其核心技术就是通过imageView来播放动画,点击button时来停止当前播放的动画开始击打地鼠的动画.话不多说直接上代码. 这是添加当前的背景图片,然 ...

  5. c++多线程崩溃错误1

    主线程中的子线程没有jion,导致主线程马上结束,子线程对象被释放掉,而子线程还在后台继续执行导致崩溃 int main() OBJ = classA() OBJ.START()//在start函数中 ...

  6. 怎样在xcode中使用storyboard

    StoryBoard是iOS 5的新特征,目的是取代历史悠久的NIB/XIB,对于已经习惯了xib文件的孩子们来说,StoryBoard还不是那么熟悉.经过两天的研究,有了一些心得,在此分享. 一.怎 ...

  7. 移植busybox-1.21.1

    busybox官网:www.busybox.net 1.解压 # tar jxvf busybox-1.21.1.tar.bz2 2.配置 # cd busybox-1.21.1 # make men ...

  8. uva 10161 Ant on a Chessboard 蛇形矩阵 简单数学题

    题目给出如下表的一个矩阵: (红字表示行数或列数) 25 24 23 22 21 5 10 11 12 13 20 9 8 7 14 19 3 2 3 6 15 18 2 1 4 5 16 17 1 ...

  9. 理解js异步的概念

    js引擎在执行的时候是单线程的,这是大家都知道的.我们先来看一段代码: <html> <head> <meta http-equiv="Content-Type ...

  10. Hibernate中load与get的区别

    1.get()采用立即加载方式,而load()采用延迟加载; ①get()方法执行的时候,会立即向数据库发出查询语句;(查询顺序:内部缓存,数据库) ②load()方法返回的是一个代理(此代理中只有一 ...