本文讲述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. Oracle 修改密码 解锁

    1.怎么修改oracle用户密码 在以SYSDBA身份登陆时可以修改其他用户的密码,比如: SQL> alter user 用户名 identified by 新密码; 用户已更改. 这个是把U ...

  2. position:absolute实现垂直居中

    一些图标通常要垂直居中 如下所示: 而css中没有直接的样式.需要我们自己调试. 我用了position:absolute;来实现. 要想使得position:absolute;有效,它的父元素必须也 ...

  3. C errors recods

    error: unterminated #ifndef 1,权限问题 2,少了#endif

  4. Ubuntu 查找命令

    Ubuntu 查找文件夹 使用find命令查找find / -name 文件夹名称 -type d找到结果中含有路径 查找命令 从根目录开始查找所有扩展名为.log的文本文件,并找出包含”ERROR” ...

  5. Linux磁盘及文件系统管理 3---- 文件系统

    1 文件系统 1 操作系统通过文件系统来管理文件及数据,磁盘或分区需要创建文件系统之后才能为操作系统使用,创建文件系统的过程称为格式化 2 没有文件系统的设备称为裸设备 3 常见的文件系统有fat32 ...

  6. 无限的路_hdu_2073(AC).java

    无限的路 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  7. android 拍照 onCreate() 调用两次的问题

    拍照的代码网上都有就不写了!自己找下就ok了! 1 旋转屏幕导致问题! 这种情况很好解决:在androidManifest.xml 中设置activity 添加属性   android:configC ...

  8. javascript常用的内置对象实用操作

    1.indexOf() 方法  -----这个方法比较常用 返回某个指定的字符串值在字符串中首次出现的位置 使用格式:stringObject.indexOf(substring, startpos) ...

  9. JavaScript学习笔记——JS中的变量复制、参数传递和作用域链

    今天在看书的过程中,又发现了自己目前对Javascript存在的一个知识模糊点:JS的作用域链,所以就通过查资料看书对作用域链相关的内容进行了学习.今天学习笔记主要有这样几个关键字:变量.参数传递.执 ...

  10. asp.net访问母版页控件方法

    一.使用多种方式为内容页加载母版页默认情况下是给单个内容页指定一个母版页加载,当多个内容页需加载到同一个母版页时,我们可以通过配置文件为多个内容页批量加载母版页,另外,还可以在PreInit事件中动态 ...