生产者消费者模式
一个线程作为生产者,一个线程作为消费者。生产者每生产一次,消费者就消费一次。生产者每次生产的商品数量以及消费者每次消费的数量用随机数产生。每一次的生产的商品数量和上一次剩余的商品数量之和不能超过1000.
package cn.javasm.demo;
public class TestDemo {
public static void main(String[] args) {
Product product = new Product();
new Thread(new Producer(product)).start();
new Thread(new Consumer(product)).start();
}
}
class Product{
// 商品数量
private int count;
// 规定true是生产,false是消费
public boolean flag = true;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
// 生产者
class Producer implements Runnable{
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
while (true){
synchronized (product) {
if (!product.flag){
try {
product.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// 生产商品
// 本次能生产的最大数量
int max = 1000 - product.getCount();
// 计算本次生产的实际数量
int count = (int)(Math.random() * (max + 1));
// 计算本次能提供的商品数量
product.setCount(product.getCount() + count);
System.out.println("本次生产的商品数量是:" + count + "个,本次提供的商品数量是" + product.getCount());
product.flag = false;
product.notify();
}
}
}
}
// 消费者
class Consumer implements Runnable{
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
while (true){
synchronized (product){
if (product.flag){
try {
product.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// 计算本次消费的商品数量
int count = (int)(Math.random() * (product.getCount() + 1));
// 计算本次剩余的商品数量
product.setCount(product.getCount() - count);
System.out.println("本次消费的商品数量是:" + count + ",本次剩余的商品数量是" + product.getCount());
product.flag = true;
product.notify();
}
}
}
}
package cn.javasm.demo;
//消费者生产者
public class TestDemo {
public static void main(String[] args) {
Product product = new Product();
new Thread(new Producer(product)).start();
new Thread(new Producer(product)).start();
new Thread(new Consumer(product)).start();
new Thread(new Consumer(product)).start();
}
}
class Product{
// 商品数量
private int count;
// 规定true是生产,false是消费
public boolean flag = true;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
// 生产者
class Producer implements Runnable{
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
while (true){
synchronized (product) {
while (!product.flag){
try {
product.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// 生产商品
// 本次能生产的最大数量
int max = 1000 - product.getCount();
// 计算本次生产的实际数量
int count = (int)(Math.random() * (max + 1));
// 计算本次能提供的商品数量
product.setCount(product.getCount() + count);
System.out.println("本次生产的商品数量是:" + count + "个,本次提供的商品数量是" + product.getCount());
product.flag = false;
// 唤醒所有的线程
product.notifyAll();
}
}
}
}
// 消费者
class Consumer implements Runnable{
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
while (true){
synchronized (product){
while (product.flag){
try {
product.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// 计算本次消费的商品数量
int count = (int)(Math.random() * (product.getCount() + 1));
// 计算本次剩余的商品数量
product.setCount(product.getCount() - count);
System.out.println("本次消费的商品数量是:" + count + ",本次剩余的商品数量是" + product.getCount());
product.flag = true;
// 唤醒所有的线程
product.notifyAll();
}
}
}
}
7 线程池
7.1 Executors[了解]
private static void demo4() {
// 创建一个可以延时的线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
long start = System.currentTimeMillis();
scheduledExecutorService.schedule(()->{
long end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println("Hello Thread");
},5, TimeUnit.SECONDS);//5为要停顿多久,TimeUnit是单位
}
private static void demo3() {
// 创建一个可以伸缩的线程池对象
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.submit(()-> System.out.println(Thread.currentThread().getName() + "执行了"));
}
}
private static void demo2() {
// 执行线程池中线程的数量
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 20; i++) {
executorService.submit(() -> System.out.println(Thread.currentThread().getName() + "执行了"));
}
}
private static void demo1() {
// 创建只有一个线程的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
// 不能并发 假设有10个任务,只有一个执行,其他9个都在等待
for (int i = 0; i < 10; i++) {
executorService.submit(()-> System.out.println(Thread.currentThread().getName() + "执行了"));
}
// 异步任务执行完之后关闭线程池
// executorService.shutdown();
// 立即关闭线程池
executorService.shutdownNow();
}
7.2 ThreadPoolExecutor[掌握]
private static void demo5() { /** * int corePoolSize, 核心线程数 * int maximumPoolSize, 允许的最大线程数量 * long keepAliveTime, 在执行的时间内回收线程 * TimeUnit unit, 时间单位 * BlockingQueue<Runnable> workQueue, 工作队列 通常使用有界队列,当有界队列满了后会采用拒绝策略,CallerRunsPolicy 是剩余的去主线程执行 * ArrayBlockingQueue 有界队列 可设置容量 * LinkedBlockingQueue 无界队列 * PriorityBlockingQueue 优先队列 * ThreadFactory threadFactory, 创建线程的工厂 Executors.defaultThreadFactory()常用的默认工厂 * RejectedExecutionHandler handler 拒绝策略 CallerRunsPolicy 去主线程执行 */
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 5, TimeUnit.MINUTES,
new ArrayBlockingQueue<>(100), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
// 执行
threadPoolExecutor.execute(()-> System.out.println(Thread.currentThread().getName() + "执行了"));
}
package cn.javasm.demo;
import java.util.concurrent.*;
public class MyThreadPool {
private MyThreadPool(){
}
// 饿汉式
private static final MyThreadPool MY_THREAD_POOL = new MyThreadPool();
// 线程池
private static final ThreadPoolExecutor POOL_EXECUTOR;
private static final ScheduledThreadPoolExecutor SCHEDULED_THREAD_POOL_EXECUTOR;
static {
// 静态代码块
// 创建对象
POOL_EXECUTOR = new ThreadPoolExecutor(10,100,10, TimeUnit.MINUTES,new ArrayBlockingQueue<>(100), Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
SCHEDULED_THREAD_POOL_EXECUTOR = new ScheduledThreadPoolExecutor(10,new ThreadPoolExecutor.CallerRunsPolicy());
}
public static MyThreadPool getInstance(){
return MY_THREAD_POOL;
}
// 异步执行任务
public void execute(Runnable runnable){
POOL_EXECUTOR.execute(runnable);
}
// 延迟执行
public void delay(Runnable runnable,long time,TimeUnit timeUnit){
SCHEDULED_THREAD_POOL_EXECUTOR.schedule(runnable,time,timeUnit);
}
// 异步执行任务
public <V> void task(Callable<V> callable){
POOL_EXECUTOR.submit(callable);
}
public void shutdown(){
SCHEDULED_THREAD_POOL_EXECUTOR.shutdown();
}
public void shutdownNow(){
SCHEDULED_THREAD_POOL_EXECUTOR.shutdownNow();
}
public void release(){
POOL_EXECUTOR.shutdown();
}
public void releaseNow(){
POOL_EXECUTOR.shutdownNow();
}
}
8 ThreadLocal
本质上是线程的一个映射
8.1 传递数据
package cn.javasm.demo;
import java.net.StandardSocketOptions;
public class TestDemo3 {
// key就是this
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
String str = "hello e";
threadLocal.set(str);
a();
}
public static void a(){
b();
}
public static void b(){
c();
}
public static void c(){
d();
}
public static void d(){
e();
}
public static void e(){
System.out.println(threadLocal.get());
}
}
8.2 解决线程安全隐患
package cn.javasm.demo;
import java.nio.channels.Pipe;
import java.util.HashMap;
public class TestDemo4 {
public static ThreadLocal<Printer> threadLocal = new ThreadLocal<>(){
// 匿名内部类,匿名内部类也相当于一个子类
@Override
protected Printer initialValue() {
return new Printer();
}
};
public static void main(String[] args) {
new Thread(new GFS()).start();
new Thread(new BFM()).start();
}
}
class Printer {
public void print(String str) {
System.out.println("打印机在打印" + str);
}
}
class GFS implements Runnable {
@Override
public void run() {
Printer printer = TestDemo4.threadLocal.get();
printer.print(printer + "高富帅");
printer.print(printer + "高富帅");
printer.print(printer + "高富帅");
}
}
class BFM implements Runnable {
@Override
public void run() {
Printer printer = TestDemo4.threadLocal.get();
printer.print(printer + "白富美");
printer.print(printer + "白富美");
printer.print(printer + "白富美");
}
}
9 线程的优先级
java中采用抢占式调度:优先级相同的情况下,随机选择一个线程执行。如果线程的优先级大,抢到CPU资源的概率更高
线程的优先级是1-10,默认是5
public static void main(String[] args) {
// 最大优先级
System.out.println(Thread.MAX_PRIORITY);
// 最小优先级
System.out.println(Thread.MIN_PRIORITY);
// 默认优先级
System.out.println(Thread.NORM_PRIORITY);
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "执行了");
}
},"线程1");
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "执行了");
}
},"线程2");
// 设置线程的优先级
thread1.setPriority(1);
thread2.setPriority(10);
thread1.start();
thread2.start();
}
10 守护线程
java中线程分为守护线程和被守护线程。所有的被守护线程执行完毕后,守护线程也会结束。
GC就是一个守护线程。
public class TestDemo6 {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
for (int i = 100000; i > 0; i--) {
System.out.println(Thread.currentThread().getName() + "还剩" + i + "滴血");
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"小兵1");
Thread t2 = new Thread(()->{
for (int i = 100000; i > 0; i--) {
System.out.println(Thread.currentThread().getName() + "还剩" + i + "滴血");
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"小兵2");
Thread t3 = new Thread(()->{
for (int i = 100000; i > 0; i--) {
System.out.println(Thread.currentThread().getName() + "还剩" + i + "滴血");
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"小兵3");
// 设置线程为守护线程
t1.setDaemon(true);
t2.setDaemon(true);
t3.setDaemon(true);
// 开启线程
t1.start();
t2.start();
t3.start();
for (int i = 10; i > 0; i--) {
System.out.println("Boss还剩" + i + "滴血");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
11 线程状态
// 创建成功还没有启动的线程
NEW,
/**
* 正在java虚拟机中执行的线程
*/
RUNNABLE,
/**
* 受阻塞并等待某个锁的线程
*/
BLOCKED,
/**
* 无限期等待另一个线程唤醒的线程
*/
WAITING,
/**
* 等待指定时间的线程
*/
TIMED_WAITING,
/**
* 已经结束的线程
*/
TERMINATED;
public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 10; i > 0; i--) {
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread.State state = thread.getState();
System.out.println(state); // NEW
// 开启线程
thread.start();
state = thread.getState();
System.out.println(state);
while (state != Thread.State.TERMINATED){
state = thread.getState();
System.out.println(state);
}
}
总结:
wait和sleep的区别?
sleep需要指定休眠时间,到点自然醒。如果线程没有锁,那么会释放执行权。如果线程有锁,不释放执行权。这个方法是设计在Thread类上的方法,是一个静态方法
wait可以指定也可以不指定时间。如果不指定时间需要唤醒。释放执行权也释放锁。这个方法是设计在Object上的一个普通方法。
注意:使用wait和notify必须结合锁来使用,而且要使用同一个锁对象