微博 Qzone 微信 JAVA多线程和并发

来源:互联网 发布:苹果电脑视频编辑软件 编辑:程序博客网 时间:2024/05/21 17:27

多线程

  • 提高了程序的执行效率,多线程同时执行,因此具有不确定性

  • 提高了资源利用率,CPU、内存等

  • 占用一定的内存空间

  • 线程越多CPU的调度开销越大

  • 程序的复杂度会上升

线程池

  • 避免线程的创建和销毁带来的性能开销(少开销)

  • 加快响应速度。任务到达时不用创建线程,直接使用线程池中的

  • 避免大量的线程间因互相抢占系统资源而阻塞的现象(避免阻塞)

  • 能对线程进行简单的管理并提供定时执行、间隔执行等功能(便于管理)

sleep和wait

  • sleep是使线程停止一段时间的方法,线程不会释放对象锁.在sleep一段时间后,线程不一定立刻回复执行,

  • wait是线程交互的时候,如果线程对一个同步对象发出wait调用,该线程会立刻暂停执行.进入等待状态,直到被唤醒,线程会放弃对象锁,使得其他线程可以使用同步控制块或者方法

多线程和并发

run和start的区别:

调用 start() 方法才会启动新线程;如果直接调用 Thread 的 run() 方法,它的行为就会和普通的方法一样;为了在新的线程中执行我们的代码,必须使用 Thread.start() 方法。run只是thread的一个普通方法,start是真正的启一个线程

关键字

  • 可见性

    可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.也就是一个线程修改的结果。另一个线程马上就能看到

    在 Java 中 volatile、synchronized 和 final 实现可见性

  • 原子性

    将操作变成原子操作

    在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性

  • 有序性

    Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性

wait和sleep

  • sleep

    在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),该线程不丢失任何监视器的所属权,sleep() 是 Thread 类专属的静态方法,针对一个特定的线程。

  • wait

    方法使实体所处线程暂停执行,从而使对象进入等待状态,导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒,该方法只能在同步方法中调用。

  • 比较

  • 本质的区别:sleep是线程的运行状态控制,wait是线程之间的通讯

  • sleep是Thread中的方法,wait是Object中的方法

  • wait() 方法进入等待状态时会释放同步锁。调用的时候需要先获得该 Object 的锁,调用 wait 后,会把当前的锁释放掉同时阻塞住。而 sleep() 方法不会释放同步锁。

  • sleep让线程从运行到阻塞,wait让线程从运行到等待队列

  • wait要用notify和notify唤醒,只能在同步环境中使用,sleep可以在任何环境中使用

notify notifyall

  • notify

    随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态,该方法只能在同步方法或同步块内部调用。

  • notifyall

    解除所有那些在该对象上调用wait方法的线程的阻塞状态,同样该方法只能在同步方法或同步块内部调用。

synchronized

是一种同步锁(CPU悲观锁),java并发编程的最常用的用于保证线程安全的方式,所有加上 synchronized 的方法和块语句,在多线程访问的时候,同一时刻只能有一个线程能够访问。

  • 修饰实例方法

    作用于当前实例加锁,进入同步代码前要获得当前实例的锁。

    实例方法不包括静态方法

  • 修饰静态方法

    作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。静态成员不专属于任何一个实例对象,是类成员,因此通过class对象锁可以控制静态成员的并发操作

  • 修饰代码块

    指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁

Lock

采用乐观锁

能完成synchronized所实现的所有功能,Lock有比synchronized更精确的线程语义和更好的性能。Lock的锁定是通过代码实现的,而synchronized是在JVM层面上实现的,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。Lock锁的范围有局限性,块范围,而synchronized可以锁住块、对象、类。在加锁和解锁处需要通过lock()和unlock()显示指出

volatile

Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。volatile 是一个特殊的修饰符,只有成员变量才能使用它。在Java并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。volatile 变量可以保证下一个读取操作会在前一个写操作之后发生。线程都会直接从内存中读取该变量并且不缓存它。这就确保了线程读取到的变量是同内存中是一致的。

volatile

能保证可见性,不能保证原子性

当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。

  • 轻量级的 synchronized

    Volatile变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。

  • volatile 并不完全是线程安全的

    用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的值。volatile很容易被误用,用来进行原子性操作。

  • 访问最新值

    Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而不是从各个线程的“工作内存”。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

  • 效率问题

    synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized

  • volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。

JAVA高级

对象序列化

很多情况下,对象内部状态是需要被持久化的,将运行中的对象状态保存下来(最直接的方式就是保存到文件系统中),在需要的时候可以还原,即使是在Java虚拟机退出的情况下

对象序列化机制是Java内建的一种对象持久化方式,可以很容易实现在JVM中的活动对象与字节数组(流)之间进行转换,使用得Java对象可以被存储,可以被网络传输,在网络的一端将对象序列化成字节流,经过网络传输到网络的另一端,可以从字节流重新还原为Java虚拟机中的运行状态中的对象

JAVA多线程和并发

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群346942462,我们一起学Java!

原创粉丝点击