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

网站首页制作模板开源商用的商城项目

网站首页制作模板,开源商用的商城项目,网站开发设计大赛,上海网络推广产品本文主要介绍了Java中的并发编程模型和常用工具类#xff0c;首先阐述了并发编程的概念及其重要性#xff0c;然后详细介绍了线程的基本概念、生命周期和状态转换、同步与互斥、死锁问题以及线程池的使用和实现原理。接着介绍了synchronized关键字和Lock接口的使用、原子变量…本文主要介绍了Java中的并发编程模型和常用工具类首先阐述了并发编程的概念及其重要性然后详细介绍了线程的基本概念、生命周期和状态转换、同步与互斥、死锁问题以及线程池的使用和实现原理。接着介绍了synchronized关键字和Lock接口的使用、原子变量和原子操作类的使用、Condition接口和ReentrantLock类的使用、CountDownLatch类和CyclicBarrier类的使用、Semaphore类和Exchanger类的使用。最后提出了并发编程的性能优化和注意事项。 一. 引言 1.1 并发编程的概念及重要性 并发编程指的是在多核心、多线程、多任务的操作系统中同时执行多个任务和线程。在计算机领域中如今大多数系统都支持并发编程因为并发编程可以大大提高系统的吞吐量和响应速度提升系统的性能和可用性。Java作为一门面向对象的编程语言也提供了一套完善的并发编程模型和工具类库为Java开发者提供了便捷的并发编程解决方案。 1.2 Java中的并发编程模型和常用工具类简介 Java中的并发编程模型基于线程和锁机制。Java中的线程是轻量级的进程每个线程都有自己的执行路径可以独立执行任务。Java中的锁机制可以保证多个线程之间的同步和互斥避免资源竞争和冲突。Java中的线程和锁机制是Java并发编程的基础。 synchronized关键字和Lock接口的使用 synchronized关键字和Lock接口是Java中的两种锁机制它们可以保证多个线程之间的同步和互斥。synchronized关键字是Java中最常用的同步机制它可以用来修饰方法或代码块。Lock接口是Java中提供的另一种同步机制它可以实现更细粒度的锁定支持可中断、可重入等高级特性。原子变量和原子操作类的使用 Java中的原子变量和原子操作类可以保证数据的原子性避免多线程之间的竞争和冲突。Java中的原子操作类包括AtomicInteger、AtomicLong、AtomicBoolean等它们都提供了一系列原子操作方法例如incrementAndGet、decrementAndGet等可以实现原子性的数值计算。Condition接口和ReentrantLock类的使用 Condition接口和ReentrantLock类是Java中用于高级同步机制的工具类。Condition接口是ReentrantLock类的一部分可以用来实现更高级别的条件等待和通知机制。ReentrantLock类是Java中提供的另一种同步机制可以实现更细粒度的锁定和高级特性例如可重入、公平性、可中断等。CountDownLatch类和CyclicBarrier类的使用 CountDownLatch类和CyclicBarrier类是Java中用于同步多线程的工具类。 二. Java中的并发编程模型 2.1 进程和线程的基本概念 进程和线程是计算机操作系统中的两个基本概念它们都可以执行任务和程序但是在实现方式、资源占用、通信方式等方面有所不同。 1. 进程 进程是计算机中执行任务的基本单位它是操作系统中的一个独立的运行实例。每个进程都有自己的独立地址空间、代码段、数据段、堆栈、文件描述符等系统资源。进程之间相互独立互不干扰。进程是资源分配的最小单位它可以分配和使用计算机中的资源如CPU、内存、文件、网络等。 2. 线程 线程是进程中的一个执行单元它是操作系统中调度的最小单位。一个进程中可以包含多个线程这些线程共享进程的地址空间和系统资源如文件、网络等。线程之间可以通过共享内存的方式进行通信但是也可能出现竞争和冲突的情况。线程是轻量级的进程创建和销毁线程的开销相对较小因此可以更加高效地利用计算机的资源。 3. 进程和线程的区别 进程和线程的主要区别在于资源占用、调度和通信方式等方面。进程是资源分配的最小单位它可以分配和使用计算机中的资源但是进程之间的通信需要通过IPCInter-Process Communication机制开销相对较大。线程是轻量级的进程它共享进程的地址空间和系统资源因此线程之间的通信和调度开销相对较小。但是线程之间可能出现竞争和冲突的情况需要进行同步和互斥操作。 2.2 线程的生命周期和状态转换 线程的生命周期包括五种状态新建状态、就绪状态、运行状态、阻塞状态和死亡状态。这些状态可以通过不同的方法进行转换下面是每个状态的含义、转换条件 新建状态New 线程被创建但是还没有开始运行的状态此时线程并没有分配到CPU资源只是一个空壳子。新建状态的线程可以通过start()方法启动。就绪状态Runnable 线程被分配到CPU资源并且可以运行的状态但是并不一定正在执行等待CPU调度。就绪状态的线程可以通过线程调度器进行调度进入运行状态。运行状态Running 线程正在执行的状态正在占用CPU资源执行任务。运行状态的线程可以通过sleep()、yield()、wait()等方法进入阻塞状态也可以通过线程调度器的调度进入就绪状态。阻塞状态Blocked 线程因为某些原因无法执行任务暂时放弃CPU资源的状态。阻塞状态包括多种类型等待阻塞wait、同步阻塞synchronized、其他阻塞sleep、join、park等。当阻塞状态结束后线程可以重新进入就绪状态等待CPU调度。死亡状态Dead 线程执行完任务或者被强制终止线程生命周期结束的状态。死亡状态的线程无法再次进入其他状态。 参考文章​​https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.State.html​​ 2.3 线程的同步与互斥 线程同步是指多个线程在共享数据时按照一定的规则进行访问和操作以避免数据的混乱和错误。线程互斥是指多个线程在对共享数据进行访问时通过一些机制防止多个线程同时对数据进行操作从而避免数据的冲突和错误。 在Java中线程同步和互斥是通过锁机制实现的。锁是一个标识用来保护共享资源只有持有锁的线程才能访问共享资源。Java提供了两种锁机制synchronized关键字和Lock接口。 synchronized关键字是Java中最基本的锁机制它是一种隐式锁只需要在方法或者代码块前加上synchronized关键字即可实现同步和互斥。synchronized关键字的作用是确保同一时间只有一个线程可以进入同步代码块或方法并且在执行完同步代码块或方法后会自动释放锁。 Lock接口是Java中的另一种锁机制它是一种显示锁需要手动加锁和释放锁。Lock接口提供了更加灵活和精细的锁控制比如可以设置超时时间、多个条件变量等。 线程同步和互斥可以有效避免多个线程对共享数据的冲突和错误保证程序的正确性和稳定性。但是如果同步和互斥使用不当也会带来一定的性能问题因此需要在使用时考虑好锁的粒度、锁的持有时间和锁的竞争情况等因素。 2.4 线程的死锁问题 线程死锁是指在多线程并发的程序中两个或多个线程因为相互等待对方释放资源而陷入一种无限等待的状态从而导致程序无法继续执行的问题。简单来说就是两个或多个线程互相持有对方需要的资源并且都在等待对方释放资源从而导致程序无法继续执行。 下面是一个简单的死锁示例 public class DeadlockExample {private static Object resource1 new Object();private static Object resource2 new Object();public static void main(String[] args) {Thread thread1 new Thread(() - {synchronized (resource1) {System.out.println(Thread 1: Holding resource 1...);try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread 1: Waiting for resource 2...);synchronized (resource2) {System.out.println(Thread 1: Holding resource 1 and 2...);}}});Thread thread2 new Thread(() - {synchronized (resource2) {System.out.println(Thread 2: Holding resource 2...);try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread 2: Waiting for resource 1...);synchronized (resource1) {System.out.println(Thread 2: Holding resource 1 and 2...);}}});thread1.start();thread2.start();} } 在这个例子中有两个线程分别持有resource1和resource2两个资源并且都在等待对方释放资源。如果运行这个程序就会陷入死锁状态程序无法继续执行。 为了避免死锁问题我们需要遵循以下原则 避免一个线程同时获取多个锁。避免一个线程在锁内部占用多个资源尽量保证每个锁只占用一个资源。尝试使用定时锁使用lock.tryLock(timeout)来替代使用内部锁机制。对于数据库锁加锁和解锁必须在一个数据库事务中执行否则会出现死锁情况。 三. Java中的并发编程工具类 3.1 synchronized关键字和Lock接口的使用 synchronized关键字 synchronized关键字是Java中最基本的同步机制可以用于实现线程的同步和互斥。synchronized关键字可以应用于方法和代码块两种形式。 synchronized方法 synchronized方法可以用于保证同一时刻只有一个线程可以访问该方法。当一个线程访问synchronized方法时其他线程必须等待该线程执行完毕后才能访问该方法。 public synchronized void synchronizedMethod() {// do something } synchronized代码块 synchronized代码块可以用于保证同一时刻只有一个线程可以访问该代码块。synchronized代码块需要指定一个锁对象只有获取该锁对象的线程才能访问该代码块。 Object lock new Object(); public void synchronizedBlock() {synchronized(lock) {// do something} } Lock接口 Lock接口是Java中提供的另一种同步机制相比于synchronized关键字Lock接口具有更加灵活的控制能力。Lock接口定义了加锁和释放锁的方法可以手动控制线程的同步和互斥。 加锁和释放锁 Lock接口定义了两个核心方法lock()和unlock()。lock()方法用于加锁只有获取锁的线程才能进入临界区执行代码。unlock()方法用于释放锁使得其他线程可以获取该锁。 Lock lock new ReentrantLock(); public void lockMethod() {lock.lock();try {// do something} finally {lock.unlock();} } 锁的重入 与synchronized关键字不同Lock接口可以支持锁的重入。当一个线程已经获取了锁并且在临界区内嵌套了另一个加锁操作时该线程仍然可以正常执行。 Lock lock new ReentrantLock(); public void reentrantLock() {lock.lock();try {// do somethinglock.lock();try {// do something} finally {lock.unlock();}} finally {lock.unlock();} } 3.2 原子变量和原子操作类的使用 原子变量 Java提供了一些原子变量类型例如AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference等可以直接在多线程环境下使用保证操作的原子性。 下面是AtomicInteger的使用方式 AtomicInteger count new AtomicInteger(0); count.getAndIncrement(); // 原子地增加计数器 需要注意的是虽然原子变量能够保证操作的原子性但并不能保证线程安全因此需要考虑其他的同步机制。 原子操作类 除了原子变量类型之外Java还提供了一些原子操作类例如AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray等可以对数组中的元素进行原子操作。 下面是AtomicIntegerArray的使用方式 AtomicIntegerArray array new AtomicIntegerArray(10); array.getAndIncrement(0); // 原子地对数组元素增加1 需要注意的是原子操作类的使用方式和原子变量类型类似同样需要考虑其他的同步机制。 总的来说原子变量和原子操作类是Java提供的保证操作原子性的机制可以有效避免竞态条件问题提高多线程程序的性能和正确性。但需要注意的是它们并不能完全保证线程安全仍然需要考虑其他的同步机制。 3.3 Condition接口和ReentrantLock类的使用 ReentrantLock类是一个可重入的互斥锁它提供了与synchronized关键字类似的功能但相比synchronized关键字更灵活能够实现更加复杂的锁定操作。同时ReentrantLock类还提供了一些高级功能例如Condition接口能够实现更加灵活的线程间通信。 ReentrantLock的基本用法 ReentrantLock类的基本用法与synchronized关键字类似可以用来实现互斥锁保护共享资源。 下面是ReentrantLock的基本使用方式 // 定义一个ReentrantLock对象 ReentrantLock lock new ReentrantLock();// 获取锁 lock.lock(); try {// 访问共享资源 } finally {// 释放锁lock.unlock(); } 需要注意的是和synchronized关键字一样ReentrantLock也需要在finally块中释放锁以确保能够释放锁资源。 Condition接口 Condition接口是ReentrantLock的一个高级功能能够实现更加灵活的线程间通信。Condition接口可以用来实现等待/通知模式使得线程能够更加精确地控制等待和唤醒的条件。 下面是Condition接口的基本使用方式 // 定义一个Condition对象 Condition condition lock.newCondition();// 等待条件 condition.await();// 唤醒等待条件的线程 condition.signal(); 需要注意的是Condition接口的等待和唤醒操作必须在ReentrantLock的锁保护下进行否则会抛出IllegalMonitorStateException异常。 ReentrantLock和Condition的综合应用 下面是一个使用ReentrantLock和Condition接口实现生产者消费者模式的示例代码 import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock;public class ProducerConsumerExample {private static final int MAX_CAPACITY 10;private ReentrantLock lock new ReentrantLock();private Condition notEmpty lock.newCondition();private Condition notFull lock.newCondition();private int count 0;public void produce() throws InterruptedException {lock.lock();try {while (count MAX_CAPACITY) {notFull.await();}count;System.out.println(Produced, count count);notEmpty.signal();} finally {lock.unlock();}}public void consume() throws InterruptedException {lock.lock();try {while (count 0) {notEmpty.await();}count--;System.out.println(Consumed, count count);notFull.signal();} finally {lock.unlock();}} } 3.4 CountDownLatch类和CyclicBarrier类的使用 CountDownLatch CountDownLatch是一个计数器它的作用是允许一个或多个线程等待一组事件的完成。CountDownLatch有一个计数器计数器的初始值为一个正整数每当一个线程完成了一个事件计数器的值就减一当计数器的值为0时表示所有事件都已经完成此时所有等待该事件的线程就可以继续执行。 使用CountDownLatch的步骤如下 1创建一个CountDownLatch对象并指定计数器的初始值。 2在等待事件的线程中调用CountDownLatch对象的await()方法进行等待直到计数器的值变为0。 3在完成事件的线程中完成事件后调用CountDownLatch对象的countDown()方法计数器的值减一。 示例代码如下 import java.util.concurrent.CountDownLatch;public class CountDownLatchTest {public static void main(String[] args) {final CountDownLatch latch new CountDownLatch(3); // 3个事件需要等待new Thread(() - {try {Thread.sleep(1000);System.out.println(事件1完成);} catch (InterruptedException e) {e.printStackTrace();} finally {latch.countDown(); // 计数器减一}}).start();new Thread(() - {try {Thread.sleep(2000);System.out.println(事件2完成);} catch (InterruptedException e) {e.printStackTrace();} finally {latch.countDown(); // 计数器减一}}).start();new Thread(() - {try {Thread.sleep(3000);System.out.println(事件3完成);} catch (InterruptedException e) {e.printStackTrace();} finally {latch.countDown(); // 计数器减一}}).start();try {latch.await(); // 等待所有事件完成System.out.println(所有事件已完成);} catch (InterruptedException e) {e.printStackTrace();}} } CyclicBarrier 创建CyclicBarrier对象指定屏障点的数量和达到屏障点时执行的任务。在每个需要等待屏障点的线程中调用await()方法等待其他线程到达屏障点。当指定数量的线程都调用了await()方法后CyclicBarrier会执行指定的任务然后释放所有等待的线程继续执行。 下面是一个简单的示例演示如何使用CyclicBarrier import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {public static void main(String[] args) {int n 3;CyclicBarrier barrier new CyclicBarrier(n, () - {System.out.println(所有线程已到达屏障点开始执行任务);});for (int i 0; i n; i) {new Thread(() - {try {System.out.println(Thread.currentThread().getName() 到达屏障点);barrier.await();System.out.println(Thread.currentThread().getName() 继续执行);} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}).start();}} } 在上面的示例中我们创建了一个CyclicBarrier对象指定了屏障点的数量为3并且指定了所有线程到达屏障点后要执行的任务。然后我们创建了3个线程每个线程在到达屏障点后调用了await()方法等待其他线程到达屏障点。当3个线程都到达屏障点后CyclicBarrier会执行指定的任务然后释放所有等待的线程继续执行。 3.5 Semaphore类和Exchanger类的使用 Semaphore类 Semaphore类是一个计数信号量用于控制同时访问某个资源的线程数量。Semaphore维护了一个可配置的许可证数量线程可以通过acquire()方法获取许可证release()方法释放许可证。当许可证被全部占用时后续线程需要等待其他线程释放许可证后才能获取到许可证。 Semaphore类的常用方法 acquire()获取一个许可证如果没有许可证则阻塞等待。acquire(int permits)获取指定数量的许可证如果没有足够的许可证则阻塞等待。release()释放一个许可证。release(int permits)释放指定数量的许可证。availablePermits()获取当前可用的许可证数量。 Semaphore类的使用示例 import java.util.concurrent.Semaphore;public class SemaphoreDemo {private static final int THREAD_COUNT 30;private static ExecutorService threadPool Executors.newFixedThreadPool(THREAD_COUNT);private static Semaphore semaphore new Semaphore(10); // 设置最多允许10个线程同时访问public static void main(String[] args) {for (int i 0; i THREAD_COUNT; i) {threadPool.execute(() - {try {semaphore.acquire(); // 获取许可证System.out.println(Thread.currentThread().getName() 获取到许可证开始执行任务);Thread.sleep(5000); // 模拟任务执行时间System.out.println(Thread.currentThread().getName() 执行任务完毕释放许可证);semaphore.release(); // 释放许可证} catch (InterruptedException e) {e.printStackTrace();}});}threadPool.shutdown();} } Exchanger类 Exchanger是Java中的一个线程同步工具它允许两个线程在同一个时刻交换数据。每个线程通过调用exchange()方法来向对方交换数据当两个线程都调用了该方法后它们会交换数据并继续执行。 Exchanger的主要方法是exchange()方法它有两个重载的版本 public V exchange(V x) throws InterruptedException;public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException; 其中第一个方法将指定的数据对象与另一个线程交换如果另一个线程在同一时刻调用了exchange()方法则它的数据对象也会被返回。如果另一个线程还没有调用exchange()方法则当前线程会阻塞等待直到另一个线程调用exchange()方法为止。 第二个方法与第一个方法类似但是增加了一个超时参数。如果在指定的超时时间内没有另一个线程调用了exchange()方法则当前线程会抛出TimeoutException异常。 下面是一个简单的示例程序展示了如何使用Exchanger来交换两个线程之间的数据 import java.util.concurrent.Exchanger;public class ExchangerDemo {public static void main(String[] args) {ExchangerString exchanger new Exchanger();new Thread(() - {String data1 Hello;System.out.println(Thread1: send data1);try {String data2 exchanger.exchange(data1);System.out.println(Thread1: received data2);} catch (InterruptedException e) {e.printStackTrace();}}).start();new Thread(() - {String data1 World;System.out.println(Thread2: send data1);try {String data2 exchanger.exchange(data1);System.out.println(Thread2: received data2);} catch (InterruptedException e) {e.printStackTrace();}}).start();} } 四. 并发编程的性能优化和注意事项 尽量避免使用锁锁是并发编程中最常见的同步机制但它会引入额外的开销并且容易导致死锁和竞争条件等问题。尽量避免使用锁可以使用无锁算法、CAS操作、分段锁等替代方案。减少上下文切换在多线程环境下线程的切换会引入额外的开销。为了减少上下文切换可以使用线程池、协程等技术避免线程的创建和销毁减少线程之间的切换次数。避免共享变量共享变量是并发编程中最常见的竞争条件可能导致数据不一致和线程安全等问题。尽量避免使用共享变量可以使用线程局部变量、不可变对象等替代方案。合理使用并发容器Java提供了许多线程安全的容器类例如ConcurrentHashMap、CopyOnWriteArrayList等。合理使用这些容器类可以避免锁的竞争和死锁等问题。避免死锁死锁是并发编程中最常见的问题之一容易导致程序的挂起和性能下降。为了避免死锁可以使用避免占用多个锁、按照相同的顺序获取锁、设置超时等机制。避免过度设计并发编程是一种复杂的编程模型容易产生过度设计和不必要的优化。在编写并发程序时应该注意避免过度设计以避免代码的可读性和可维护性降低。
http://www.dnsts.com.cn/news/123874.html

相关文章:

  • 网站空间单位新闻发布会的意义
  • 可以做试卷网站数学试卷小学六wordpress主页图片不显示
  • 传奇网站装备动态图怎么做坂田网站建设
  • 微信网站建设定制青海建设工程信息网站
  • html页面网站建设中网上商城网站建设解决方案
  • 免费网站如何注册视频制作软件下载安装
  • 网站建设投标书模板app应用网站源码
  • php做网站首页企业网站报告册设计模板
  • 婚介网站方案鄂尔多斯做网站
  • 樟木头镇仿做网站如何提高seo关键词排名
  • django网站开发案例wordpress后台超慢
  • 好上手的做海报网站权重域名做网站有用么
  • 北京制作网站多少钱礼仪策划网站建设
  • 面对面视频 网站开发互联网营销推广渠道
  • 自己可以做视频网站吗做网站设计能赚钱吗
  • 做cpa必须要有网站吗怎么样做一个网站
  • 什么是二级网站推广wordpress一键 centos
  • 浙江省住房和建设厅网站php 网站版面素材
  • 成都网站网络建设wordpress博客转出
  • 河北建设网站怎么下载企业锁冯耀宗seo视频教程
  • 做网站主页图片一般多少mwordpress 亚马逊插件
  • 游戏网站风控怎么做广西住房和城乡建设厅招聘
  • 南京做企业网站公司德邦物流公司现代物流网站建设与开发
  • 颜色选取网站如何快速的制作h5页面
  • 西安做网站推广农庄网站模板
  • 新手怎么做电商在哪个网站数字logo创意设计
  • 装修房子的app软件哪个好谷歌seo详细教学
  • 找人做网站服务器不是自己的怎么办高清的建设工程人员查询
  • 为女朋友做的网站牟长青 做网站推广的四个基本要点
  • 下载的网站模板怎么去掉域名前的图标中国建筑工程信息资讯网