企业网站的总体设计营销型网站一套

当前位置: 首页 > news >正文

企业网站的总体设计,营销型网站一套,电子宣传册如何制作,北京网站制作招聘面对苦难的态度#xff1a;《病隙碎笔》“不断的苦难才是不断地需要信心的原因#xff0c;这是信心的原则#xff0c;不可稍有更动。” 孤独与心灵的成长#xff1a;《我与地坛》“孤独的心必是充盈的心#xff0c;充盈得要流溢出来要冲涌出去#xff0c;便渴望有人呼应他… 面对苦难的态度《病隙碎笔》“不断的苦难才是不断地需要信心的原因这是信心的原则不可稍有更动。” 孤独与心灵的成长《我与地坛》“孤独的心必是充盈的心充盈得要流溢出来要冲涌出去便渴望有人呼应他、收留他、理解他。” 目录 上一篇博客习题讲解 使用ReentrantLock实现生产者-消费者模式 为什么在某些情况下ReentrantLock的表现优于synchronized 设计一个场景说明何时应该选择使用读写锁而不是普通的互斥锁 实现一个简单的银行账户类 公平锁与非公平锁 Shutdown() vs ShutdownNow() Future 和 FutureTask 创建可暂停和恢复所有线程池任务的系统 知识讲解 第9章 Tomcat线程池技术 9.1 自定义 ThreadPoolExecutor 9.2 Tomcat任务队列 9.3 Tomcat任务线程 9.4 Tomcat任务线程工厂 9.5 Tomcat连接器与线程池 9.6 创建 Tomcat 线程池 9.7 Web服务器异步环境 9.8 Web服务器 NIO 9.9 本章习题 上一篇博客习题讲解 Java多线程与线程池技术详解八 Java多线程与线程池技术详解八-CSDN博客文章浏览阅读428次点赞19次收藏8次。如果只有傻瓜才相信梦想那么就叫我大傻瓜吧“想走的路不好走想做人不好做都说是身不由己不是废话么。己不由心身又岂能由己https://blog.csdn.net/speaking_me/article/details/144394346?spm1001.2014.3001.5501 使用ReentrantLock实现生产者-消费者模式 生产者-消费者模式是并发编程中的经典问题它涉及到两个或多个线程之间的协调工作。为了确保数据的一致性和线程的安全性通常会使用锁机制来控制对共享资源的访问。下面是一段使用ReentrantLock实现生产者-消费者模式的示例代码 import java.util.LinkedList; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class ProducerConsumerExample {private final int MAX_SIZE 5;private final LinkedListInteger list new LinkedList();private final Lock lock new ReentrantLock();private final Condition notFull lock.newCondition();private final Condition notEmpty lock.newCondition();public void produce(int value) throws InterruptedException {lock.lock();try {while (list.size() MAX_SIZE) {System.out.println(Buffer is full, waiting…);notFull.await();}list.add(value);System.out.println(Produced: value);notEmpty.signalAll();} finally {lock.unlock();}}public Integer consume() throws InterruptedException {lock.lock();try {while (list.isEmpty()) {System.out.println(Buffer is empty, waiting…);notEmpty.await();}Integer value list.removeFirst();System.out.println(Consumed: value);notFull.signalAll();return value;} finally {lock.unlock();}} } 这段代码中我们创建了一个固定大小的缓冲区并通过ReentrantLock和两个Condition对象notFull和notEmpty来管理生产和消费的过程。 为什么在某些情况下ReentrantLock的表现优于synchronized ReentrantLock提供了比synchronized更灵活的功能例如可以尝试获取锁、支持公平锁、允许锁中断等特性。此外在高并发场景下ReentrantLock的性能可能优于synchronized因为它避免了线程进入内核态的阻塞状态。不过需要注意的是在低并发的情况下synchronized的性能表现可能会更好。 设计一个场景说明何时应该选择使用读写锁而不是普通的互斥锁 假设有一个缓存系统其中读取操作远远多于写入操作。在这种情况下如果使用普通的互斥锁则每次读取时都会阻止其他读取操作的发生即使它们不会相互影响。而使用读写锁如ReentrantReadWriteLock则可以在没有写入操作发生时允许多个读取操作同时进行从而提高了系统的并发度和响应速度。 实现一个简单的银行账户类 对于银行账户类我们可以分别使用synchronized和ReentrantLock来保证线程安全。以下是两种实现方式 使用synchronized关键字 public class BankAccountSynchronized {private double balance;public synchronized void deposit(double amount) {// 存款逻辑}public synchronized boolean withdraw(double amount) {// 取款逻辑return true;} } 使用ReentrantLock import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class BankAccountReentrantLock {private double balance;private final Lock lock new ReentrantLock();public void deposit(double amount) {lock.lock();try {// 存款逻辑} finally {lock.unlock();}}public boolean withdraw(double amount) {lock.lock();try {// 取款逻辑return true;} finally {lock.unlock();}} } 两者的主要区别在于synchronized是隐式锁自动管理锁的获取与释放而ReentrantLock需要显式地调用lock()和unlock()方法来控制锁的行为。 公平锁与非公平锁 公平锁所有等待线程按照请求锁的顺序获得锁这有助于防止饥饿现象的发生但吞吐量较低。非公平锁允许新到达的线程插队即有可能跳过已经在等待的线程直接获得锁这种方式能提高吞吐量但在极端情况下可能导致部分线程长时间得不到执行机会。 例如在一个高频交易系统中为了最大化吞吐量可以选择使用非公平锁而在一个任务调度系统中为了保证每个任务都能得到及时处理可能更适合采用公平锁。 Shutdown() vs ShutdownNow() shutdown()方法会停止接收新的任务并将试图终止所有正在运行的任务但它不会立即终止已提交的任务。相反shutdownNow()将尝试取消所有未开始的任务并且会中断正在执行的任务。因此shutdownNow()更激进可能会导致一些任务被中途打断适用于紧急情况下的快速关闭。 Future 和 FutureTask Future接口表示异步计算的结果提供了检查计算是否完成、等待计算完成以及获取结果的方法。FutureTask是一个实现了Runnable和Future接口的具体类它可以包装一个Callable或Runnable对象使得可以通过调用其run()方法启动任务并通过get()方法获取结果或等待任务完成。此外还可以调用cancel(boolean mayInterruptIfRunning)来尝试取消任务。 创建可暂停和恢复所有线程池任务的系统 要实现这样一个系统可以考虑为每个任务添加一个状态标志位用于指示任务是否应该暂停。当接收到暂停指令时所有任务都将检查自己的状态并根据需要暂停执行。恢复时再次检查状态以决定是否继续执行。需要注意的是这种设计可能会引入额外的复杂性比如如何同步状态变更以及处理潜在的死锁问题。 知识讲解 第9章 Tomcat线程池技术 9.1 自定义 ThreadPoolExecutor Tomcat的线程池是基于Java的ThreadPoolExecutor实现的但为了适应Web服务器的需求它做了许多定制化处理。在创建自定义的ThreadPoolExecutor时可以指定核心线程数corePoolSize、最大线程数maximumPoolSize、空闲线程存活时间keepAliveTime、任务队列workQueue等参数。Tomcat中的ThreadPoolExecutor与标准JDK版本不同它增加了对提交任务计数的支持并且在执行任务失败时会尝试将任务重新加入到任务队列中。 // 自定义ThreadPoolExecutor构造函数 public class CustomThreadPoolExecutor extends ThreadPoolExecutor {public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueueRunnable workQueue) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);// 预热所有核心线程prestartAllCoreThreads();} } 9.2 Tomcat任务队列 Tomcat的任务队列并非直接使用JDK提供的阻塞队列而是使用了一个名为TaskQueue的类它是LinkedBlockingQueue的一个子类。这个队列实现了特殊的逻辑当线程池中的线程数量小于最大线程数时它会优先创建新的线程来处理任务而不是将任务放入队列只有在线程数达到最大值后才会考虑将任务放入队列。 // TaskQueue 类的部分实现 public class TaskQueue extends LinkedBlockingQueueRunnable {Overridepublic boolean offer(Runnable o) {// 如果线程池大小未达到最大则返回false表示队列已满if (parent.getPoolSizeNoLock() parent.getMaximumPoolSize()) {return false;}// 否则调用父类方法添加任务return super.offer(o);} } 9.3 Tomcat任务线程 每个任务线程都是由TaskThreadFactory创建出来的它们继承自Thread类并且可以根据需要设置线程名称前缀、守护状态以及优先级。这些线程负责从任务队列中取出任务并执行。 // TaskThreadFactory 创建线程的方法 public class TaskThreadFactory implements ThreadFactory {private final String namePrefix;private final boolean daemon;private final int threadPriority;public TaskThreadFactory(String namePrefix, boolean daemon, int threadPriority) {this.namePrefix namePrefix;this.daemon daemon;this.threadPriority threadPriority;}Overridepublic Thread newThread(Runnable r) {Thread t new Thread(r, namePrefix - threadNumber.getAndIncrement());t.setDaemon(daemon);t.setPriority(threadPriority);return t;} } 9.4 Tomcat任务线程工厂 如上所示TaskThreadFactory用于创建线程实例并允许开发者配置线程的名字、是否为守护进程及优先级。 9.5 Tomcat连接器与线程池 Tomcat的连接器Connector负责监听客户端请求并通过线程池分配线程来处理这些请求。根据不同的I/O模型BIO/NIO/APR可以选择不同的连接器实现方式。例如默认情况下NIO模式下使用的NioEndpoint会创建一个或多个Acceptor线程来接收新连接并将其交给Poller线程进行读写操作。 9.6 创建 Tomcat 线程池 在Tomcat启动过程中AbstractEndpoint#createExecutor()方法会被调用来初始化线程池。这里不仅设置了线程池的基本属性还预热了所有的核心线程以确保一旦有请求到来就能立即得到处理。 public void createExecutor() {internalExecutor true;TaskQueue taskqueue new TaskQueue();TaskThreadFactory tf new TaskThreadFactory(getName() -exec-, daemon, getThreadPriority());executor new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(),60L, TimeUnit.SECONDS, taskqueue, tf);taskqueue.setParent((ThreadPoolExecutor) executor); } 9.7 Web服务器异步环境 对于支持异步Servlet的应用程序来说Tomcat提供了AsyncContext机制使得可以在非阻塞的方式下调用业务逻辑从而提高系统的并发处理能力。 下面是一个简单的例子展示了如何使用AsyncContext protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {final AsyncContext asyncContext request.startAsync();asyncContext.start(() - {try {// 调用业务方法businessMethod(asyncContext.getResponse());asyncContext.complete();} catch (Exception e) {asyncContext.setError(e);asyncContext.complete();}}); }private void businessMethod(HttpServletResponse response) throws Exception {// 模拟长时间运行的任务Thread.sleep(5000);response.getWriter().println(Hello World!); } 9.8 Web服务器 NIO Tomcat的NIO实现依赖于Java NIO库它允许单个线程管理多个套接字连接。这减少了所需的线程数并提高了性能。NioEndpoint类包含了对NIO特性的具体实现包括但不限于选择器Selector、通道Channel和缓冲区Buffer的操作。 // NioEndpoint 中的部分代码片段 Override protected void startInternal() throws Exception {// 创建并启动Poller线程poller new Poller();Thread pollerThread new Thread(poller, getName() -Poller);pollerThread.setPriority(threadPriority);pollerThread.setDaemon(true);pollerThread.start();startAcceptorThreads(); } 9.9 本章习题 考虑到篇幅限制此处不提供完整的练习题目但是建议读者尝试完成以下任务来加深理解 实现自己的ThreadPoolExecutor并测试其行为。修改TaskQueue的行为使其在某些条件下拒绝接受新任务。使用AsyncContext创建一个异步Servlet应用。探索Tomcat源码中关于NIO的具体实现细节。