Java深入解析_并发编程专题(多线程之间通信、线程池)


一、多线程之间通信

1.生产者与消费者

package com.itmayiedu;

// 共享对象
class Res {

	// 姓名
	public String name;
	// 性别
	public String sex;
}

// 生产这线程
class IntThread extends Thread {
	public Res res;

	public IntThread(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
		int count = 0; // 1
		while (true) {
			synchronized (res) {
				if (count == 0) {
					res.name = "小红";
					res.sex = "女";
				} else {
					res.name = "小军";
					res.sex = "男";
				}
				count = (count + 1) % 2;// 0 1 0 1 0 1
			}

		}
	}
}

// 读取线程
class OutThread extends Thread {

	public Res res;

	public OutThread(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
		while (true) {
			synchronized (res) {
				System.out.println(res.name + "," + res.sex);

			}

		}
	}

}

public class Test0001 {
	public synchronized static void main(String[] args) throws InterruptedException {

		Res res = new Res();
		IntThread intThread = new IntThread(res);
		OutThread outThread = new OutThread(res);
		intThread.start();
		outThread.start();
	}
}

2.wait与notify区别

package com.itmayiedu;

// 共享对象
class Res {

	// 姓名
	public String name;
	// 性别
	public String sex;
	// 为true情况下 允许读,不能写
	// 为false情况下 允许写,不能读。
	public boolean flag = false;

}

// 生产这线程
class IntThread extends Thread {
	public Res res;

	public IntThread(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
		int count = 0; // 1
		while (true) {
			synchronized (res) {
				if (res.flag) {
					try {
						res.wait();// 釋放当前锁对象
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
				if (count == 0) {
					res.name = "小红";
					res.sex = "女";
				} else {
					res.name = "小军";
					res.sex = "男";
				}
				count = (count + 1) % 2;// 0 1 0 1 0 1
				res.flag = true;// 标记当前线程为等待
				res.notify();// 唤醒被等待的线程
			}

		}
	}
}

// 读取线程
class OutThread extends Thread {

	public Res res;

	public OutThread(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
		while (true) {
			synchronized (res) {
				try {
					if (!res.flag) {
						res.wait();
					}
					Thread.sleep(1000);
				} catch (Exception e) {
					// TODO: handle exception
				}

				System.out.println(res.name + "," + res.sex);
				res.flag = false;
				res.notify();
			}

		}
	}

}

public class Test0001 {
	public synchronized static void main(String[] args) throws InterruptedException {

		Res res = new Res();
		IntThread intThread = new IntThread(res);
		OutThread outThread = new OutThread(res);
		intThread.start();
		outThread.start();
	}
}

在这里插入图片描述

wait、notify方法总结:
1.因为涉及到对象锁,他们必须都放在synchronized中来使用. Wait、Notify一定要在synchronized里面进行使用。
2.Wait必须暂定当前正在执行的线程,并释放资源锁,让其他线程可以有机会运行
3. notify/notifyall: 唤醒因锁池中的线程,使之运行

注意:一定要在线程同步中使用,并且是同一个锁的资源

3.阻塞队列与非阻塞队列

在这里插入图片描述

阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列。

1.ArrayDeque, (数组双端队列)
2.PriorityQueue, (优先级队列)
3.ConcurrentLinkedQueue, (基于链表的并发队列)
4.DelayQueue, (延期阻塞队列)(阻塞队列实现了BlockingQueue接口)
5.ArrayBlockingQueue, (基于数组的并发阻塞队列)
6.LinkedBlockingQueue, (基于链表的FIFO阻塞队列)
7.LinkedBlockingDeque, (基于链表的FIFO双端阻塞队列)
8.PriorityBlockingQueue, (带优先级的无界阻塞队列)
9.SynchronousQueue (并发同步阻塞队列)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.使用并发队列实现生产者与消费者

class ProducerThread implements Runnable {
	private BlockingQueue<String> blockingQueue;
	private AtomicInteger count = new AtomicInteger();
	private volatile boolean FLAG = true;

	public ProducerThread(BlockingQueue<String> blockingQueue) {
		this.blockingQueue = blockingQueue;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "生产者开始启动....");
		while (FLAG) {
			String data = count.incrementAndGet() + "";
			try {
				boolean offer = blockingQueue.offer(data, 2, TimeUnit.SECONDS);
				if (offer) {
					System.out.println(Thread.currentThread().getName() + ",生产队列" + data + "成功..");
				} else {
					System.out.println(Thread.currentThread().getName() + ",生产队列" + data + "失败..");
				}
				Thread.sleep(1000);
			} catch (Exception e) {

			}
		}
		System.out.println(Thread.currentThread().getName() + ",生产者线程停止...");
	}

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

}

class ConsumerThread implements Runnable {
	private volatile boolean FLAG = true;
	private BlockingQueue<String> blockingQueue;

	public ConsumerThread(BlockingQueue<String> blockingQueue) {
		this.blockingQueue = blockingQueue;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "消费者开始启动....");
		while (FLAG) {
			try {
				String data = blockingQueue.poll(2, TimeUnit.SECONDS);
				if (data == null || data == "") {
					FLAG = false;
					System.out.println("消费者超过2秒时间未获取到消息.");
					return;
				}
				System.out.println("消费者获取到队列信息成功,data:" + data);

			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

}

public class Test0008 {

	public static void main(String[] args) {
		BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>(3);
		ProducerThread producerThread = new ProducerThread(blockingQueue);
		ConsumerThread consumerThread = new ConsumerThread(blockingQueue);
		Thread t1 = new Thread(producerThread);
		Thread t2 = new Thread(consumerThread);
		t1.start();
		t2.start();
		//10秒后 停止线程..
		try {
			Thread.sleep(10*1000);
			producerThread.stop();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

}

5.线程池的作用

在这里插入图片描述

6.executors四种线程池用法

package com.itmayiedu;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test0001 {

	 public static void main(String[] args) {
		 //可以缓存的线程池
		 ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
		 for (int i = 0; i < 10; i++) {
			 final int temp=i;
			 // 可执行线程 execute 方法表示启动线程
			 newCachedThreadPool.execute(new Runnable() {
					
					@Override
					public void run() {
                        System.out.println(Thread.currentThread().getId()+",i"+temp);
					}
				});
		}
		
	}
	
}

package com.itmayiedu;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test0002 {

	public static void main(String[] args) {
		// 控制并发数的线程池
		ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
		for (int i = 0; i < 10; i++) {
			final int temp = i;
			newFixedThreadPool.execute(new Runnable() {

				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName() + "," + temp);
				}
			});
		}
	}

}

package com.itmayiedu;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test0003 {

	public static void main(String[] args) {
		// 可以定时线程池
		ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3);
		for (int i = 0; i < 10; i++) {
			final int temp = i;
			newScheduledThreadPool.schedule(new Runnable() {
				public void run() {
					System.out.println(Thread.currentThread().getName()+",i:" + temp);
				}
			}, 3, TimeUnit.SECONDS);
		}
	}

}

package com.itmayiedu;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test0004 {

	public static void main(String[] args) {
		ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
		for (int i = 0; i < 10; i++) {
			final int temp = i;
			newSingleThreadExecutor.execute(new Runnable() {
				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName() + ",i:" + temp);
				}
			});
		}
	}

}

7.线程池实现原理

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值