哪个网站可以做兼职,青浦营销型网站建设,临沂网站制作,网站计数器代码js线程通信 应用场景#xff1a;生产者和消费者问题 假设仓库中只能存放一件产品#xff0c;生产者将生产出来的产品放入仓库#xff0c;消费者将仓库中产品取走消费 如果仓库中没有产品#xff0c;则生产者将产品放入仓库#xff0c;否则停止生产并等待#xff0c…线程通信 应用场景生产者和消费者问题 假设仓库中只能存放一件产品生产者将生产出来的产品放入仓库消费者将仓库中产品取走消费 如果仓库中没有产品则生产者将产品放入仓库否则停止生产并等待直到仓库中的产品被消费者取走为止 如果仓库中放有产品则消费者可以将产品取走消费否则停止消费并等待直到仓库中再次放入产品为止
线程通信-分析 这是一个线程同步问题生产者和消费者共享同一个资源并且生产者和消费者之间相互依赖互为条件 对于生产者没有生产产品之前要通知消费者等待而生产了产品之后又需要马上通知消费者消费 对于消费者在消费之后要通知生产者已经结束消费需要生产新的产品以供消费 在生产者消费者问题中仅有synchronized是不够的 synchronized可阻止并发更新同一个共享资源实现了同步 synchronized不能用来实现不同线程之间的消息传递通信 java提供了几个方法解决线程之间的通信问题均是Object类的方法都只能在同步方法或者同步代码块中使用否则会抛出异常IIIegalMonitorStateException 方法名 作用 wait() 表示线程一直等待直到其他线程通知与sleep不同会释放锁 wait(long timeout) 指定等待的毫秒数 notify() 唤醒一个处于等待状态的线程 notifyAll() 唤醒同一个对象上所有调用wait()方法的线程优先级别高的线程优先调度
解决方式1 并发协作模型”生产者/消费者模式“ --管程法 生产者负责生产数据的模块可能是方法对象线程进程 消费者负责处理数据的模块可能是方法对象线程进程 缓冲区消费者不能直接使用生产者的数据他们之间有个”缓冲区“ 生产者将生产好的数据放入缓冲区消费者从缓冲区拿出数据
解决方式2 并发协作模型”生产者/消费者模式“ --信号灯法
方式1代码
package com.kuang.thread;/*
线程通信
应用场景生产者和消费者问题假设仓库中只能存放一件产品生产者将生产出来的产品放入仓库消费者将仓库中产品取走消费如果仓库中没有产品则生产者将产品放入仓库否则停止生产并等待直到仓库中的产品被消费者取走为止如果仓库中放有产品则消费者可以将产品取走消费否则停止消费并等待直到仓库中再次放入产品为止线程通信-分析
这是一个线程同步问题生产者和消费者共享同一个资源并且生产者和消费者之间相互依赖互为条件对于生产者没有生产产品之前要通知消费者等待而生产了产品之后又需要马上通知消费者消费对于消费者在消费之后要通知生产者已经结束消费需要生产新的产品以供消费在生产者消费者问题中仅有synchronized是不够的synchronized可阻止并发更新同一个共享资源实现了同步synchronized不能用来实现不同线程之间的消息传递通信java提供了几个方法解决线程之间的通信问题均是Object类的方法都只能在同步方法或者同步代码块中使用否则会抛出异常IIIegalMonitorStateException方法名 作用wait() 表示线程一直等待直到其他线程通知与sleep不同会释放锁wait(long timeout) 指定等待的毫秒数notify() 唤醒一个处于等待状态的线程notifyAll() 唤醒同一个对象上所有调用wait()方法的线程优先级别高的线程优先调度解决方式1并发协作模型”生产者/消费者模式“ --管程法生产者负责生产数据的模块可能是方法对象线程进程消费者负责处理数据的模块可能是方法对象线程进程缓冲区消费者不能直接使用生产者的数据他们之间有个”缓冲区“生产者将生产好的数据放入缓冲区消费者从缓冲区拿出数据解决方式2并发协作模型”生产者/消费者模式“ --信号灯法*///测试生产者消费者模型--》利用缓冲区解决管程法//生产者消费者产品缓冲区
public class TestPC {public static void main(String[] args) {Synchronizer container new Synchronizer();//创建缓冲区//创建生产者线程Producers producer new Producers(container);//创建消费者线程Consumer consumer new Consumer(container);//启动生产者和消费者线程producer.start();consumer.start();}
}//生产者
class Producers extends Thread{Synchronizer container;//定义一个容器public Producers(Synchronizer container){this.container container;}Overridepublic void run() {for (int i 1; i 20; i) {System.out.println(生产了第 i 个产品);container.push(new Product(i));//将产品放入缓冲区try{Thread.sleep(1000);//模拟生产耗时} catch (InterruptedException e){e.printStackTrace();}}}
}//消费者
class Consumer extends Thread{Synchronizer container;//定义一个容器public Consumer(Synchronizer container){this.container container;}Overridepublic void run() {for (int i 1; i 20; i) {Product product container.pop();//从缓冲区(仓库)取出产品System.out.println(消费了第 product.id 个产品);try{Thread.sleep(3000);//模拟消费耗时} catch (InterruptedException e){e.printStackTrace();}}}
}//产品
class Product {int id;//产品编号public Product(int id){this.id id;}
}//缓冲区商店/仓库
class Synchronizer {//需要一个容器大小Product[] products new Product[10];//容器计数器int count 0;//生产者放入产品public synchronized void push(Product product) {//如果容器满了就需要等待消费者消费,生产者等待if(count products.length) {System.out.println(缓冲区(仓库)已满生产者等待...);try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没有满我们就需要丢入产品(放入产品)products[count] product;count;System.out.println(生产者生产放入第 product.id 个产品当前缓冲区里有了 count 个产品);this.notifyAll();//通知消费者可以消费了}//消费者消费产品public synchronized Product pop(){//如果容器为空消费者等待while(count 0){try {System.out.println(缓冲区为空消费者等待...);wait();//消费者等待}catch (InterruptedException e){e.printStackTrace();}}//如果容器不为空取出产品count--;Product product products[count];System.out.println(消费者消费取出了第 product.id 个产品当前缓冲区里还剩 count 个产品);//如果缓冲区仓库为空没有商品了立即通知生产者生产商品if (count 0) {System.out.println(缓冲区为空仓库没有商品了通知生产者生产商品...);this.notifyAll();//通知生产者可以生产了}return product;}
}
这段代码实现了一个经典的生产者-消费者模型通过线程间的通信和同步机制wait() 和 notify()来协调生产者和消费者的行为。以下是代码的详细分析和实现逻辑 代码结构 TestPC 类 主类包含 main 方法用于启动生产者和消费者线程。 创建了一个缓冲区Synchronizer 对象并启动生产者和消费者线程。 Producers 类 生产者线程负责生产产品并将其放入缓冲区。 通过 container.push() 方法将产品放入缓冲区。 Consumer 类 消费者线程负责从缓冲区取出产品并消费。 通过 container.pop() 方法从缓冲区取出产品。 Product 类 表示产品的类包含一个 id 属性用于标识产品的编号。 Synchronizer 类 缓冲区类用于存储产品。 提供了 push() 和 pop() 方法分别用于生产者和消费者操作缓冲区。 使用 wait() 和 notify() 实现线程间的通信和同步。 代码逻辑
1. 生产者逻辑 生产者线程通过 run() 方法不断生产产品。 每次生产一个产品后调用 container.push() 方法将产品放入缓冲区。 如果缓冲区已满生产者会调用 wait() 进入等待状态直到消费者消费产品后唤醒它。 生产者生产完产品后会调用 notifyAll() 通知消费者可以消费了。
2. 消费者逻辑 消费者线程通过 run() 方法不断从缓冲区取出产品并消费。 每次消费一个产品时调用 container.pop() 方法从缓冲区取出产品。 如果缓冲区为空消费者会调用 wait() 进入等待状态直到生产者生产产品后唤醒它。 消费者消费完产品后如果发现缓冲区为空会调用 notifyAll() 通知生产者可以生产了。
3. 缓冲区逻辑 缓冲区是一个固定大小的数组products用于存储产品。 count 表示当前缓冲区中的产品数量。 push() 方法用于生产者将产品放入缓冲区。如果缓冲区已满生产者会等待。 pop() 方法用于消费者从缓冲区取出产品。如果缓冲区为空消费者会等待。 使用 wait() 和notifyAll() 实现线程间的通信和同步。 代码执行流程 生产者生产产品 生产者生产产品并调用 push() 方法将产品放入缓冲区。 如果缓冲区已满生产者会进入等待状态。 消费者消费产品 消费者调用 pop() 方法从缓冲区取出产品。 如果缓冲区为空消费者会进入等待状态。 线程通信 当生产者放入产品后会调用 notifyAll() 唤醒等待的消费者。 当消费者取出产品后如果发现缓冲区为空会调用 notifyAll() 唤醒等待的生产者。
关键点 线程同步 使用 synchronized 关键字确保对缓冲区的操作是线程安全的。 生产者和消费者通过 wait() 和notifyAll() 实现线程间的通信。 缓冲区的作用 缓冲区作为共享资源协调了生产者和消费者的操作。 生产者将产品放入缓冲区消费者从缓冲区取出产品。 线程通信 当缓冲区满时生产者会等待直到消费者消费产品后唤醒它。 当缓冲区为空时消费者会等待直到生产者生产产品后唤醒它。 改进点 在消费者消费完产品后如果发现缓冲区为空会立即通知生产者生产商品确保缓冲区不会长时间处于空的状态。
方式2代码
package com.kuang.thread;//测试生产者消费者问题2信号灯法标志位解决
//并发协作模型“生产者/消费者模式” --》信号灯法
public class TestPC2 {public static void main(String[] args) {TV tv new TV();new Player(tv).start();new Watcher(tv).start();}
}//生产者--》演员
class Player extends Thread{TV tv;public Player(TV tv){this.tv tv;}Overridepublic void run() {for (int i 0; i 20; i) {if (i%20){this.tv.play(快乐大本营);}else {this.tv.play(抖音-记录美好生活);}}}
}//消费者--》观众
class Watcher extends Thread{TV tv;public Watcher(TV tv){this.tv tv;}Overridepublic void run() {for (int i 0; i 20; i) {tv.watch();}}
}//产品--》节目
class TV{//演员表演观众等待//观众观看演员等待String voice;//表演的节目boolean flag true;//定义标志词flag//表演public synchronized void play(String voice){if (!flag){//如果flag为假try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(演员表演了 voice);//通知观众观看this.notifyAll();//通知唤醒this.voice voice;this.flag !this.flag;}//观看public synchronized void watch(){if (flag) {try{this.wait();} catch (InterruptedException e){e.printStackTrace();}}System.out.println(观众观看了 voice);//通知演员表演this.notifyAll();this.flag !this.flag;}
}
这段代码实现了一个简单的生产者-消费者模型使用了“信号灯法”也称为标志位法来协调生产者和消费者之间的同步。代码的核心思想是通过一个共享的标志位flag来控制生产者和消费者的执行顺序确保生产者和消费者交替执行。
代码结构分析 TestPC2 类 这是程序的入口类包含 main 方法。 在 main 方法中创建了一个 TV 对象共享资源并启动了一个生产者线程Player和一个消费者线程Watcher。 Player 类 这是生产者线程类继承自 Thread。 在 run 方法中生产者会循环 20 次交替生产两种节目“快乐大本营”和“抖音-记录美好生活”。 生产者通过调用 TV 对象的 play 方法来生产节目。 Watcher 类 这是消费者线程类继承自 Thread。 在 run 方法中消费者会循环 20 次调用 TV 对象的 watch 方法来消费节目。 TV 类 这是共享资源类包含了生产者和消费者共享的数据和方法。 voice 字段表示当前播放的节目。 flag 字段是一个标志位用于控制生产者和消费者的执行顺序。 play 方法和 watch 方法都是同步方法synchronized确保同一时间只有一个线程可以访问这些方法。
代码执行流程 生产者Player执行流程 生产者调用 play 方法时首先检查 flag 是否为 false。如果 flag 为 false表示消费者正在消费生产者需要等待调用 wait 方法。 如果 flag 为 true生产者可以执行生产操作输出节目名称并调用 notifyAll 方法唤醒等待的消费者线程。 生产完成后生产者将 flag 设置为 false表示消费者可以开始消费。 消费者Watcher执行流程 消费者调用 watch 方法时首先检查 flag 是否为 true。如果 flag 为 true表示生产者正在生产消费者需要等待调用 wait 方法。 如果 flag 为 false消费者可以执行消费操作输出当前播放的节目名称并调用 notifyAll 方法唤醒等待的生产者线程。 消费完成后消费者将 flag 设置为 true表示生产者可以开始生产。
关键点 synchronized 关键字确保 play 和 watch 方法是线程安全的同一时间只有一个线程可以执行这些方法。 wait 和 notifyAll 方法用于线程间的通信和同步。wait 方法使当前线程进入等待状态直到其他线程调用 notifyAll 方法唤醒它。 flag 标志位用于控制生产者和消费者的执行顺序。flag 为 true 时生产者可以生产flag 为 false 时消费者可以消费。
总结
这段代码通过使用 synchronized、wait 和 notifyAll 方法以及一个标志位 flag实现了一个简单的生产者-消费者模型。生产者和消费者交替执行确保生产者生产一个节目后消费者才能消费反之亦然。这种模式可以有效地解决多线程环境下的同步问题。
线程池
使用线程池 背景经常创建和销毁、使用量特别大的资源比如并发情况下的线程对性能影响很大。 思路提前创建好多个线程放入线程池中使用时直接获取使用完放回池中。 可以避免频繁创建销毁、使用时直接获取使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处 提高响应速度减少了创建新线程的时间 降低资源消耗重复利用线程池中线程不需要每次都创建 便于线程管理... corePoolSize:核心池的大小 maximumPoolSize最大线程数 keepAliveTime线程没有任务时最多保持多长时间后会终止
JDK 5.0起提供了线程池相关APIExecutorService和Executors ExecutorService真正的线程池接口。常见子类ThreadPoolExecutor void execute(Runnable command):执行任务/命令没有返回值一般用来执行Runnable TFutureTsubmit(CallableTtask):执行任务有返回值一般又来执行Callable void shutdown():关闭连接池
Executors工具类、线程池的工厂类用于创建并返回不同类型的线程池
练习代码
package com.kuang.thread;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*
线程池
使用线程池
背景经常创建和销毁、使用量特别大的资源比如并发情况下的线程对性能影响很大。
思路提前创建好多个线程放入线程池中使用时直接获取使用完放回池中。
可以避免频繁创建销毁、使用时直接获取使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。好处提高响应速度减少了创建新线程的时间降低资源消耗重复利用线程池中线程不需要每次都创建便于线程管理...corePoolSize:核心池的大小maximumPoolSize最大线程数keepAliveTime线程没有任务时最多保持多长时间后会终止JDK 5.0起提供了线程池相关APIExecutorService和Executors
ExecutorService真正的线程池接口。常见子类ThreadPoolExecutorvoid execute(Runnable command):执行任务/命令没有返回值一般用来执行RunnableTFutureTsubmit(CallableTtask):执行任务有返回值一般又来执行Callablevoid shutdown():关闭连接池Executors工具类、线程池的工厂类用于创建并返回不同类型的线程池*/
//测试线程池
public class TestPool {public static void main(String[] args) {//1.创建服务创建线程池//newFixedThreadPool 参数为线程池大小ExecutorService service Executors.newFixedThreadPool(10);//创建线程池//执行线程service.execute(new MyThread());service.execute(new MyThread());service.execute(new MyThread());service.execute(new MyThread());//关闭连接service.shutdownNow();}
}class MyThread implements Runnable{Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}
这段代码演示了如何使用 Java 的线程池ExecutorService来管理和执行多线程任务。线程池是一种用于管理多个线程的机制它可以避免频繁创建和销毁线程从而提高程序的性能和资源利用率。
代码结构分析 TestPool 类 这是程序的入口类包含 main 方法。 在 main 方法中创建了一个固定大小的线程池并使用线程池执行多个任务。 MyThread 类 这是一个实现了 Runnable 接口的类表示一个可以被线程执行的任务。 在 run 方法中任务简单地输出当前线程的名称。
代码执行流程 创建线程池 使用 Executors.newFixedThreadPool(10) 创建一个固定大小为 10 的线程池。这意味着线程池中最多可以同时运行 10 个线程。 ExecutorService 是线程池的接口Executors 是一个工具类提供了创建不同类型线程池的静态方法。 提交任务 使用 service.execute(new MyThread()) 方法向线程池提交任务。execute 方法接受一个 Runnable 对象并将其放入线程池中等待执行。 代码中提交了 4 个 MyThread 任务。 任务执行 线程池中的线程会从任务队列中取出任务并执行。每个任务的 run 方法会被调用输出当前线程的名称。 由于线程池的大小是 10而任务只有 4 个因此这些任务会被线程池中的线程立即执行。 关闭线程池 使用 service.shutdownNow() 方法关闭线程池。shutdownNow 会尝试停止所有正在执行的任务并返回等待执行的任务列表。 关闭线程池后不能再向线程池提交新的任务。
关键点 线程池的优势 提高响应速度线程池中的线程是预先创建好的任务提交后可以直接执行减少了创建线程的时间。 降低资源消耗线程池中的线程可以重复利用避免了频繁创建和销毁线程的开销。 便于线程管理线程池提供了对线程的统一管理可以控制线程的数量、生命周期等。 ExecutorService 接口 execute(Runnable command)执行一个没有返回值的任务。 submit(CallableT task)执行一个有返回值的任务返回一个 Future 对象。 shutdown()平缓关闭线程池等待所有任务执行完毕。 shutdownNow()立即关闭线程池尝试停止所有正在执行的任务。 Executors 工具类 提供了创建不同类型线程池的静态方法如 newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor 等。
总结
这段代码展示了如何使用 Java 的线程池来管理和执行多线程任务。通过使用线程池可以有效地管理线程资源避免频繁创建和销毁线程从而提高程序的性能和资源利用率。线程池是多线程编程中非常重要的工具特别适用于需要处理大量短期任务的场景。