多线程
提高了程序的执行效率,多线程同时执行,因此具有不确定性
提高了资源利用率,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培训教程:Java多线程并发教程”的内容,希望对大家有帮助,如有疑问,请在线咨询,有专业老师随时为你服务。
相关文章
零基础怎么自学Java,完整版Java学习路线图
你还在纠结学Java,是自学还是去培训班吗
一个标准的Java程序员如何进阶?
Java学习路线清单,快速进阶Java
Java编程初学者要如何进阶