java 多线程的同步与通信

java 多线程的同步与通信,典型应用生产者与消费者模型

当我们使用生产者消费者来进行操作同一资源时


class Resource{
	private int count;
	private String name;
	public void set(String name) {
		this.name = name;
		System.out.println(Thread.currentThread().getName()+"	生产者	"+name);
	}
	public void out()
	{
		System.out.println(Thread.currentThread().getName()+"	生产者	"+name);
	}
}
class Producer implements Runnable{
	Resource resource;
	public Producer(Resource resource) {
		this.resource = resource;
	}
	public void run(){
		while(true)
		{
			resource.set("面包");
		}
	}
}
class Consumer implements Runnable{
	Resource resource;
	public Consumer(Resource resoure)
	{
		this.resource = resource;
	}
	public void run() {
		while(true) {
		resource.out();
		}
	}
}
public class TestDemo {

	public static void main(String[] args) {
		Resource r = new Resource();
		Producer p1 = new Producer(r);
		Consumer c1 = new Consumer(r);
		//创建线程任务
		Thread t1 = new Thread(p1);
		Thread t2 = new Thread(c1);
		//开启多线程
		t1.start();
		t2.start();
	}
}

该方式会出现以下情况

Thread-0	生产者	面包 20207
Thread-0	生产者	面包 20208
Thread-0	生产者	面包 20209
Thread-0	生产者	面包 20210
Thread-0	生产者	面包 20211
Thread-0	生产者	面包 20212
Thread-0	生产者	面包 20213
Thread-0	生产者	面包 20214
Thread-1	消费者	面包 20207
Thread-1	消费者	面包 20215
Thread-1	消费者	面包 20215
Thread-1	消费者	面包 20215
Thread-1	消费者	面包 20215
Thread-1	消费者	面包 20215

说明不同步,生产运行结果数据错误,已经被生产的商品才被消费到,因为,例如当线程由生产者占用时生产了面包1,切换到消费者线程,消费者线程还没来得及输出就切回生产者线程,生产完面包2 3之后,消费者线程从刚刚断开地方执行,消费面包1,出现线程安全问题,加入同步来解决,使用同步函数

线程安全问题

  • 1多个线程在操作共享数据
  • 2线程任务操作共享数据的代码有多条(运算有多个)

使用同步代码块或同步函数来进行同步时,会使得当一个线程1执行该同步代码块或者同步函数时,拿到锁,若该线程未将同步代码块或同步函数执行完,就切换到另一线程2,则线程2不会执行,因为没有锁。当线程1执行完会释放锁,线程2 拿到锁,然后执行。

class Resource{
	private int count;
	private String name;
	public synchronized void set(String name) {
		this.name = name+" "+count;
		count++;
		System.out.println(Thread.currentThread().getName()+"	生产者	"+this.name);
		
	}
	public synchronized void out()
	{
		System.out.println(Thread.currentThread().getName()+"	消费者	"+this.name);
	}
}
class Producer implements Runnable{
	Resource resource;
	public Producer(Resource resource) {
		this.resource = resource;
	}
	public void run(){
		while(true)
		{
			resource.set("面包");
		}
	}
}
class Consumer implements Runnable{
	Resource resource;
	public Consumer(Resource resource)
	{
		this.resource = resource;
	}
	public void run() {
		while(true) {
		resource.out();
		}
	}
}
public class TestDemo {

	public static void main(String[] args) {
		Resource r = new Resource();
		Producer p1 = new Producer(r);
		Consumer c1 = new Consumer(r);
		//创建线程任务
		Thread t1 = new Thread(p1);
		Thread t2 = new Thread(c1);
		//开启多线程
		t1.start();
		t2.start();
	}
}

发现问题已解决,不会再消费到之前很早期的商品,但是还是会出现连续生产却没有被消费,一个商品被消费多次的情况。

Thread-0	生产者	面包 91301
Thread-0	生产者	面包 91302
Thread-0	生产者	面包 91303
Thread-1	消费者	面包 91303
Thread-1	消费者	面包 91303
Thread-1	消费者	面包 91303
Thread-1	消费者	面包 91303
Thread-1	消费者	面包 91303
Thread-1	消费者	面包 91303

线程间的通信

我们的希望是生产者生产一个面包,消费者就消费掉一个面包,也就是说生产者生产了商品后,应该告诉消费者来消费,这是生产者应该处等待状态
消费者消费了商品后,就应该告诉生产者生产

等待唤醒机制

  • wait();让线程处于等待状态,其实就让线程临时存储到了线程池中
  • notify();会唤醒线程池中任意一个等待的线程
  • notifyAll();唤醒线程池中所有的等待线程
  • 记住这些方法必须使用再同步中,因为必须要标识wait notify 等方法所属的锁
  • 同一个锁上的notify,只能唤醒该锁上的被wait的线程
class Resoure1
{
	private boolean flag = false;//false的时候标志为空,true的时候标识为非空
	private String name;
	private int count;
	public synchronized void  set(String name)
	{	
		while(flag)
		{ 
			try{wait();}catch(Exception e) {}
		}
		//给成员变量赋值并加上编号
		this.name= name+count;
		count++;
		System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
		flag = true;
		notify();
	}
	public synchronized void out()
	{

		while(!flag)
		{
			try{wait();}catch(Exception e) {}
		}
		System.out.println(Thread.currentThread().getName()+"..消费者.."+this.name);
		flag = false;
		notify();		
	}
}
//2.描述生产者,具备着自己的任务
class Producer1 implements Runnable
{
	private Resoure1 r;
	public Producer1(Resoure1 r) {
		this.r = r;
	}
	@Override
	public void run() {
		while(true)
		{
			r.set("面包");
		}
		
	}
	
}
//3.描述消费者,具备着自己的任务
class Consumer1 implements Runnable
{
	private Resoure1 r;
	public Consumer1(Resoure1 r) {
		this.r = r;
	}
	@Override
	public void run() {
		while(true)
		{
			r.out();
		}
		
	}
	
}
public class TestDemo4 {

	public static void main(String[] args) {
	
		Resoure1 resoure = new Resoure1();
		
		//创建线程任务
		Producer1 p1 = new Producer1(resoure);
		Consumer1 c1 = new Consumer1(resoure);
		//创建线程
		Thread t1 =new Thread(p1);
		Thread t2 =new Thread(c1);
		
		//开启线程
		t1.start();
		t2.start();
	

猜你喜欢

转载自blog.csdn.net/qq_29424305/article/details/84172851
今日推荐