并发:多个线程操作同一个资源,不是同时执行,而是交替执行,单核CPU交替执行时间间隔特别短,
并行:并行指的是同时执行,多核CPU,每一个线程使用一个单独CPU,
并发编程:指多个任务在一个时间段重复执行的结构
并发编程的三个特性:
1.原子性
原子操作:不可分割的操作,中间不会被其他线程打断,不需要同步操作
多个原子操作合起来就需要使用到同步
原子性指的是一次操作或者多个操作,要么全部执行,要么全部都不执行
例如:
int a = 10 ; //原子操作
a++; // 不是原子操作
int b = a; //不是原子操作
a = a+1; // 不是操作
2.可见性
当在一个线程中队某一共享变量进行了修改,那么另外的线程可以立即看到修改后的新值
3.顺序性
程序代码在执行过程中的先后顺序
单线程环境指令重排序不会影响最终的结果
如何实现高并发(提高系统的并发能力)
垂直扩展(硬件):
增强计算机的硬件性能:增加cpu核数,内存升级,磁盘扩容
提高系统的架构能力:使用cache提高效率
水平扩展(软件):
集群,分布式
线程是组成进程的基本单位,cpu调用的最小单位
进程是计算机上的独立的应用程序,资源分配的最小单位
1.内存空间
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
2.安全性
多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
3.效率
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式进行。
1).New----Thread对象的状态,在没有start之前,该线程不存在时;
2).Runnable----Thread对象进入Runnable状态必须调用start方法,此时真正的在JVM中创建了一个线程,线程启动之后并不会立即去执行,该状态的线程位于可运行线程池中,等待操作系统的资源,比如:处理器 (在等待cpu的使用权;
3).Running----一旦CPU选中了线程,那么此时该线程能够去执行自己的逻辑代码;
4).Blocked----等待一个监视器锁进入到synchronized block/method,处理这个里面的逻辑代码在某一时刻只能允许一个线程执行,其他线程只能去等待,这种情况下,等待的线程处于Blocked状态,处于Blocked状态的线程获取到了监视器锁,则应该从Blocked状态转换到Runnable状态;
5).WAITING/TIMED_WAITING----等待状态
6).Terminated----该状态表示线程的最终状态,在该状态中线程不会切换到其他的状态,线程进入该状态,意味着线程的整个生命周期已经结束;
进入Terminated状态的三种情况:
1.线程运行正常结束
2.线程运行出错
3.JVM crash,导致所有线程结束
1.start()
开启线程
2.sleep()
Thread.sleep() 使得当前线程进入指定毫秒数的休眠
休眠有一个重要特性,不会放弃monitor锁的使用权
jdk1.5之后,引入枚举TimeUnit
3.yield()
让步一次cpu时间片,只是对于cpu调度器的一个提示
4.joind()
在线程A中,join某个线程B,会使得线程A进入等待,直到线程B结束了自己的生命周期或者达到给定的时间,那么在此期间,线程A处于等待状态
join方法可以使得线程顺序执行
5.interrupt()
中断线程的方法
----Thread.sleep() |
----Object.wait() |
----Thread.join() |
----Selector.wakeUp() |
这些为可中断方法,不和interrupt方法同时使用(调用这些方法后,线程处于阻塞状态,如果另一线程调用被阻塞线程的interrupt方法,则会打断这个线程的阻塞状态,并会报错)
6.isInterrupted()
判断线程是否被中断
7.interrupted()
静态方法,底层调用isInterrupted方法,检测线程是否被中断
第一次调用interrupted方法会返回true,并且会立即擦除线程中的中断状态位,之后调用都会返回false
yield和sleep的区别:
1)sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给优先级低的线程以运行的机会,而yield()方法只会给相同优先级或者更高优先级的线程以运行机会。
2)线程执行sleep()方法后会转入阻塞状态,所以,执行sleep()方法的线程在指定的时间内肯定不会被执行,而yield()方法只是使当前线程重新回到可执行状态,所以执行yield()方法的线程有可能在进入到可执行状态后马上又被执行。
3)sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常。
4)sleep()方法比yield()方法(跟操作系统)具有更好的可移植性。