java多线程之生产者消费者

(1)生产者和消费者问题(1)--对象的创建

package PC;

public class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("名字"+s.name+"年龄"+s.age);
    }

}
package PC;

public class SetThread implements Runnable{
    private Student s;
    public SetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        s.age =11;
        s.name="111";
    }

}
package PC;

public class Student {
    String name;
    int age;
    
}
package PC;
public class StudentDemo {

    public static void main(String[] args) {
    
        Student s = new Student();
        
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        
        t1.start();
        t2.start();
    }
    
}

运行结果   null  0

分析:线程运行时,每一次设置和获取值得时候,都会创建一个新的对象,解决方法:在外界把这个对象创建出来,通过构造方法传递对象。

(2)生产者和消费者问题(2)

package PC1;
/**
 * 
 * @author Administrator
 * 
 * 为了数据的效果好。加入了循环和判断,给出不同的值,产生新的问题
 *  问题:
 *       A:同一个数据出现多次,
 *         CPU的一点点时间片,就足够执行多次
 *       B:姓名和年龄不匹配
 * 
 *       线程安全问题:
 *          A: 是否是多线程环境
 *          B:是否有共享数据
 *          C:是否有多条语句操作共享数据
 *          
 *      解决方案:加锁
 */
public class StudentDemo {

    public static void main(String[] args) {
    
        Student s = new Student();
        
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        
        t1.start();
        t2.start();
    }
    
}
package PC1;

public class Student {
    String name;
    int age;
    
}
package PC1;

public class SetThread implements Runnable{
    private Student s;
    private int x = 0;
    public SetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            if(x % 2 == 0 ){
                s.age =11;   // 做到这里,被别人抢到了执行权,线程安全问题
                s.name="111";
            }else{
                s.age =22;
                s.name="222";// 做到这里,被别人抢到了执行权线程安全问题
            }
            x++;
        }
        
    }

}
package PC1;

public class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        while(true){
            // TODO Auto-generated method stub
            System.out.println("名字"+s.name+"年龄"+s.age);
        }
    }

}

运行结果

1111  11

1111  11

2222 22

改进方案

package PC1;
/**
 * 
 * @author Administrator
 * 
 * 为了数据的效果好。加入了循环和判断,给出不同的值,产生新的问题
 *  问题:
 *       A:同一个数据出现多次,
 *         CPU的一点点时间片,就足够执行多次
 *       B:姓名和年龄不匹配
 * 
 *       线程安全问题:
 *          A: 是否是多线程环境
 *          B:是否有共享数据
 *          C:是否有多条语句操作共享数据
 *          
 *      解决方案:加锁
 *          注意:(1)不同种类的对象都要加锁
 *              (2)不同种类的线程加的锁必须是同一把锁
 */        
public class StudentDemo {

    public static void main(String[] args) {
    
        Student s = new Student();
        
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        
        t1.start();
        t2.start();
    }
    
}
package PC1;

public class SetThread implements Runnable{
    private Student s;
    private int x = 0;
    public SetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            synchronized (s) {
                if(x % 2 == 0 ){
                    s.age =11;   // 做到这里,被别人抢到了执行权,线程安全问题
                    s.name="111";
                }else{
                    s.age =22;
                    s.name="222";// 做到这里,被别人抢到了执行权线程安全问题
                }
                x++;
            }
            
        }
        
    }

}
package PC1;

public class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        while(true){
            // TODO Auto-generated method stub
            synchronized (s) {
                System.out.println("名字"+s.name+"年龄"+s.age);
            } 
            
        }
    }

}

现在解决了 线程安全问题,但是还是会出现多条数据,主要是因为,cup短时间内会执行多次

 (3)消费者生产者问题(3)

        上面将线程安全的问题解决了,下面还存在一些问题。

          (1).如果消费者先抢到cup执行权,就回去消费数据,但是现在使用的是默认值。此时的数据没有意义,

                    应该等着数据有意义,再去消费。

          (2)如果生产者先抢到cpu执行权,就回去产生数据,但是呢,它产生完数据后,还继续拥有执行权,

                    它有继续产生数据。这还是有问题的,你应该等到消费者吧数据消费掉,然后在产生。

                  解决为题的思路是:

                             A :生产者

                                            先看是否有数据,有数据等待,没有数据生产,生产之后,通知消费者消费。

                             B:消费者

                                        先看是否有数据,有数据消费,没有数据等待。通知生产者,你该生产了。

                               java提供了一种机制:等待唤醒机制。

 (4)消费者生产者之等待唤醒机制

                

package PC2;
/**
 * 
 * @author Administrator
 * 
 * 为了数据的效果好。加入了循环和判断,给出不同的值,产生新的问题
 *  问题:
 *       A:同一个数据出现多次,
 *         CPU的一点点时间片,就足够执行多次
 *       B:姓名和年龄不匹配
 * 
 *       线程安全问题:
 *          A: 是否是多线程环境
 *          B:是否有共享数据
 *          C:是否有多条语句操作共享数据
 *          
 *      解决方案:加锁
 *          注意:(1)不同种类的对象都要加锁
 *              (2)不同种类的线程加的锁必须是同一把锁
 *              
 *      问题3  虽然数据安全了 ,但是数据出现混乱,想要实现数据依次出现,通过java等待唤醒机制出现。
 *      等待唤醒:
 *           wait();
 *           notify();
 *           notifyAll();
 *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象,所以,这些方法必须定义在Object中。
 */         
public class StudentDemo {

    public static void main(String[] args) {
    
        Student s = new Student();
        
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        
        t1.start();
        t2.start();
    }
    
}

package PC2;

public class Student {
    String name;
    int age;
    
    boolean flag; // 默认没有数据,如果输true有数据
    
}

package PC2;

public class SetThread implements Runnable{
    private Student s;
    private int x = 0;
    public SetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            synchronized (s) {
                // 判断是否有数据
                if(s.flag){
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }else{
                    if(x % 2 == 0 ){
                        s.age =11;   // 做到这里,被别人抢到了执行权,线程安全问题
                        s.name="111";
                    }else{
                        s.age =22;
                        s.name="222";// 做到这里,被别人抢到了执行权线程安全问题
                    }
                    x++;
                }
                // 有数据
                s.flag = true;
                // 唤醒
                s.notify();
                }
            
        }
        
    }

}

package PC2;

public class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        while(true){
            // TODO Auto-generated method stub
            synchronized (s) {
                if(!s.flag){
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                
                System.out.println("名字"+s.name+"年龄"+s.age);
                
                // 修改标记
                s.flag = false;
                // 唤醒
                s.notify();
            }
            
        }
    }

}

运行结果

111  11

222 22

111 11

222 22

  (5)生产者消费者代码优化(Student 对象私有)

package PC2;

public class Student {
	private String name;
	private int age;
	boolean flag; // 默认没有数据,如果输true有数据

	public synchronized void set(String name,int age) {
		// 如果有数据,等待
		if(this.flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		//设置数据
		this.age = age;
		this.name = name;
		// 修改标记
		this.flag = true;
		this.notify();
	}
	public synchronized void get() {
		if(!this.flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(this.name+""+this.age);
		// 修改标记
		this.flag = false;
		this.notify();
	}


}
package PC2;

public class SetThread implements Runnable{
	private Student s;
	private int x = 0;
	public SetThread(Student s){
		this.s = s;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
					if(x % 2 == 0 ){
						s.set("11", 11);
					}else{
						s.set("22", 22);
					}
					x++;
				}
				}
			

package PC2;

public class GetThread implements Runnable{

	private Student s;
	public GetThread(Student s){
		this.s = s;
	}
	@Override
	public void run() {
		while(true){
			s.get();
		}
	}

}
package PC2;
/**
 * 
 * @author Administrator
 * 
 * 为了数据的效果好。加入了循环和判断,给出不同的值,产生新的问题
 *  问题:
 *       A:同一个数据出现多次,
 *         CPU的一点点时间片,就足够执行多次
 *       B:姓名和年龄不匹配
 * 
 *       线程安全问题:
 *          A: 是否是多线程环境
 *          B:是否有共享数据
 *          C:是否有多条语句操作共享数据
 *          
 *      解决方案:加锁
 *          注意:(1)不同种类的对象都要加锁
 *              (2)不同种类的线程加的锁必须是同一把锁
 *              
 *      问题3  虽然数据安全了 ,但是数据出现混乱,想要实现数据依次出现,通过java等待唤醒机制出现。
 *      等待唤醒:
 *           wait();
 *           notify();
 *           notifyAll();
 *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象,所以,这些方法必须定义在Object中。
 *             
 *      最终代码  :吧student对象的成员私有了,把设置和获取封装成功能,并且加了同步,直接调用方法即可。
 */         
public class StudentDemo {

	public static void main(String[] args) {
	
		Student s = new Student();
		
		SetThread st = new SetThread(s);
		GetThread gt = new GetThread(s);
		
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(gt);
		
		t1.start();
		t2.start();
	}
	
}

  

猜你喜欢

转载自www.cnblogs.com/currymds/p/9656974.html