j2se -----线程---生产者与消费者

[code]
-------------------------------------------------------------------------
生产者和消费者问题----java
我们现在生产的是信息,有两种信息的生产
信息种类1: name = 李兴华 content = Java讲师
信息种类2: name = "mldn" content = "www.mldnJava.com"
先看一个问题例子:
class Info{
private String name = "李兴华";
private String content = "Java讲师";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

class Producer implements Runnable{
private Info info = null;
public Producer(Info info){
this.info = info;
}

public void run(){
boolean isPersonInfo = false; //这个工厂生产两种东西,而且是交替生产,注意,这种东西与锁有着巨大的区别,因为他允许多个线程访问它,虽然在第一次大家都进入isPersonInfo=false的里面,但是必然有一个线程先执行完,执行完后就改变了isPersonInfo=true,那么显然这对另外一个线程来说是不合逻辑的。。。
for(int i=0;i<50;i++){
if(isPersonInfo){
this.info.setName("李兴华");
try{
Thread.sleep(90); //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
}catch(Exception e){}

this.info.setContent("java讲师");
isPersonInfo = false;
}else{
this.info.setName("mldn");
try{
Thread.sleep(90); //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
}catch(Exception e){}
this.info.setContent("www.mldnjava.com");
isPersonInfo = true;
}
}
}
}

class Consumer implements Runnable{
private Info info = null;
public Consumer(Info info){
this.info = info;
}

public void run(){
for(int i=0;i<50;i++){ //消费者休息90秒就去取东西
try{
Thread.sleep(90);
}catch(Exception e){

}
System.out.println(this.info.getName()+"--->"+this.info.getContent());
}
}
}

class ThreadCaseDemo01{
public static void main(String args[]){
Info info = new Info();
Producer pro = new Producer(info);
Consumer comsumer = new Consumer(info);
new Thread(pro).start();
new Thread(pro).start();
}
}

//以上的程序很可能被篡改。。。

我们改变下代码,因为篡改是没有原子操作,所以我们给他来个原子操作,最好把需要原子化的这些操作放到一个方法里面,然后同步方法即可。

class Info{
private String name = "李兴华";
private String content = "Java讲师";

public synchronized void set(String name,String content){
this.name = name;
try{
Thread.sleep(90); //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
}catch(Exception e){}
this.content = content;
}

public synchronized void get(){
System.out.println(this.name+"---->"+this.content);
}


}

class Producer implements Runnable{
private Info info = null;
public Producer(Info info){
this.info = info;
}

public void run(){
boolean isPersonInfo = false; //这个工厂生产两种东西,而且是交替生产
for(int i=0;i<50;i++){
if(isPersonInfo){
this.info.set("李兴华", "java讲师");
isPersonInfo = false;
}else{
this.info.set("mldn", "www.mldnjava.com");
isPersonInfo = true;
}
}
}
}

class Consumer implements Runnable{
private Info info = null;
public Consumer(Info info){
this.info = info;
}

public void run(){
for(int i=0;i<50;i++){ //消费者休息90秒就去取东西
try{
Thread.sleep(90);
}catch(Exception e){

}
this.info.get();
}
}
}

//上面的代码使得操作原子化了,但是发生了重复取东西的情况,并没有达到设置一个取走一个的目的,要解决这个问题,需要使用等待与唤醒机制

在Object类中的唤醒有两个:notify() 和notifyAll()

一般来说,等待的线程一般会按照顺序排列,如果现在使用了notify()方法的话,则会唤醒第一个等待的线程执行,如果使用notifyAll()方法的话,则会唤醒所有等待的线程,那么优先级最高的那个线程就有可能先执行

因为set和get的时候需要判断是否有人在操作,那么我们可以修改info类

class Info{
private String name = "李兴华";
private String content = "Java讲师";
// private boolean isProducing = true;//因为Info是临界区,当然他最清楚谁在里面
//修改得更加易于阅读
private boolean producerHaveLock = true;

//因为是放东西到仓库里面,当然是生产者的行为
//synchronized是为了防止多个同类线程进入
//但是他不能防止set和get操作在同一时间只能发生一个,为了使得两个毫不相关的方法也同步起来,那么只能使用一个变量来判断是否有线程在执行,并且启用wait()和notify()来同步多个方法。。。哈哈。。终于找到精髓
public synchronized void set(String name,String content){
//如果消费者在里面我就等。。。
if(!lockInProducer()){
try{super.wait(); }catch(Exception e){}
}
//----等待通过,这个时候也就是说消费者出来了后,我进行生产
this.name = name;
try{
Thread.sleep(90); //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
}catch(Exception e){}
this.content = content;
//生产完成
giveLock2Coustomer();
}

public synchronized void get(){
if(lockInProducer()){
super.wait();
}

try{
Thread.sleep(300);
}catch(Exception e){}
System.out.println(this.name+"---->"+this.content);
giveLock2Produce();
}

private void giveLock2Produce(){
producerHaveLock = true;
super.notify();
}
private void giveLock2Coustomer(){
producerHaveLock = false;
super.notify();
}
private boolean lockInProducer(){
return producerHaveLock ;
}

}


还有几个方法已经不建议使用了,因为很可能引起死锁问题。。。
suspend();挂起 resume()反挂起
stop()定制线程

如果我们现在要想停止一个线程运行怎么办。。。?

用设置标志位的方法啦。。
class MyThread implements Runnable{
private boolean isStop = true;
public void run(){
int i = 0;
while(!isStop){
System.out.println("运行了"+i+“次”);
}
}

public void stop(){
this.isStop = false;
}
}

public class Test{
public static void main(String[] args){
MyThread m = new MyThread();
Thread t = new Thread(m);
t.start();
Thread.sleep(500);
m.stop();
}
}
---------------------------------------------------------------------------
sleep和wait的区别
sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。

public class MultiThread {

public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(new Thread1()).start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new Thread2()).start();
}

private static class Thread1 implements Runnable {

public void run() {
synchronized (MultiThread.class) {
System.out.println("enter thread1...");
System.out.println("thread1 is waiting");
try {
// 释放锁有两种方式,第一种方式是程序自然离开监视器的范围,也就是离开了synchronized关键字管辖的代码范围,另一种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。这里,使用wait方法释放锁。
MultiThread.class.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread1 is going on...");
System.out.println("thread1 is being over!");
}
}
}

private static class Thread2 implements Runnable {

public void run() {
// TODO Auto-generated method stub
synchronized (MultiThread.class) {

System.out.println("enter thread2...");
System.out.println("thread2 notify other thread can release wait status..");
// 由于notify方法并不释放锁,
// 即使thread2调用下面的sleep方法休息了10毫秒,但thread1仍然不会执行,因为thread2没有释放锁,所以Thread1无法得到锁。
MultiThread.class.notify();

System.out.println("thread2 is sleeping ten millisecond...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread2 is going on...");
System.out.println("thread2 is being over!");
}
}
}
}


[/code]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值