进程是程序运行时资源分配的基本单位,一个父进程可以创建子进程来执行,父进程只负责监控什么时候释放子进程,执行动作是由子进程来完成。线程是程序执行的最小基本单位,成本小,在进程区间内共享全局资源包括一些静态变量。区别与联系:简单地说就是进程与进程间相互独立,程序宕机对其他进程的影响不大,而线程之间的联系耦合度大,其中一个失败了会导致整个进程垮掉。但是线程执行的成本低,新开的进程底层会创建数据库表去维护,同时也会新分配地址空间,所耗费的资源也是巨大的。
多线程:
并行:多个cpu或者多台机器同时执行一段处理逻辑
并发:看上去是同时执行,但是相互间是独立运行的。
线程安全:在并发的情况下,开启的多个线程执行的调度顺序不会影响最终结果。在这个过程中我们只需要关注cpu是否够用即可。线程不安全就意味着线程的调度顺序会影响最终的结果。
同步:通过人为的控制和调度,保证共享资源的多线程访问是线程安全的。如加@synchonized。线程安全的优先级高于性能。
1.线程的状态
1)新创建的线程可以启动start方法,是线程进入Runnable状态,之后获取到cpu,继续Running。
2)线程开始跑之后就有多种情景可以发生,比如说碰到了join,碰到了sleep,暂时被锁住,或者wait或者synchronized,这是能恢复的状态变成Runnable继续执行完线程。
3)线程执行完或者异常退出 则无法恢复
状态详解:
join()等价于join(0),等待无限时间,同步的效果,主线程交出控制权,由join主动执行完,再执行其余线程。join(10)表示允许单独执行10毫秒再交替执行。
sleep()意思就是谁调用就使当前的线程休眠一段时间。没有释放锁,其他线程也必须等待
wait()让线程释放对象锁,其他线程能拿去执行。等到唤醒后再拿锁继续。
notify()/notifyAll()/interrupt()唤醒线程
在锁的情境下,结合synchronized,wait,notify典型场景生产者消费者的问题。
每个java对象都配有一个monitor(监听器),非多线程的执行过程中它不会发挥作用,但是当开启锁之后,监视器就会开始发挥作用。wait跟notifiy也是在锁内同时产生效果。
多线程的内存模型volatile:main memory(主存)、working memory(线程栈),处理数据时会将值从主存加载到本地栈,完成操作后再save回去。
针对多线程取值的变量如果不是volatile或者不是final修饰的,可能会产生如下后果(同步展示的效果如果一个线程修改了某个值但是另一线程看到的还是修改前的数值)。多线程会存在缓存值,本质volatile就是不去缓存,直接取值。所以在线程安全的情况下加volatile会降低系统的属性。
https://www.cnblogs.com/wxd0108/p/5479442.html
java线程生命周期六种状态:
1)New(初始化状态)
指的是线程在代码块里被创建,但是没有在操作系统里并没有分配cpu给这个线程。仅仅是New但没有彻底激活,就是初始化状态。
2)Runnable(可运行/运行状态)
这个状态是补充初始化的机制,激活操作系统分配cpu执行,在New状态时调用start方法。
3)Blocked(阻塞状态)
这个状态不能被分配cpu,只有在synchronized时,被synchronize修饰的方法或者代码块里只能被一个线程执行,而其他竞争锁的线程就从Runnable变成了Blocked,而竞争得到锁的线程就变成了Runnable。
4)Waiting(无时间限制的等待状态)
这种情况不能被分配CPU执行的
one:Object.wait(),等到notifyAll()或者notify()唤醒
two:Thread.join(),主线程中创建线程A,等到A.join执行完才继续执行主线程。、
three:LockSupport.part(),并发包中的锁。LocalSupport.unpark(Thread thread)。
5)Time_Waiting(有时间限制的等待状态)
从Runable到witing状态
one:Object.wait(long timeout)。
two:Thread.join(long millis)。
three:Thread.sleep(long millis)。
four:LockSupport.parkNanos(Object blocked,long deadline)。
five:LockSupport.parkUntil(long deadline)。
6)Terminated(终止状态)
Thread里的interrupted()和isInterrupted()方法对比:
两个方法都是用来判断线程当前的中断状态。
interrupted()是静态方法:内部实现是调用的当前线程的isInterrupted(),并且会重置当前线程的中断状态。
isInterrupted()是实例方法,是调用该方法的对象所表示的那个线程的isInterrupted(),不会重置当前线程的中断状态。
isInterrupted()比如中断状态返回true时,用了interrupted()方法,第二次调用不会让这个结果变成false,而Interrupted()就会让结果重置成false,这就是本质的区别。
相比new Thread创建线程的弊端,java提供了四种线程池。
原先的new Thread每次新建对象性能差;新建的线程间缺乏管理,相互竞争,占用过多资源。因为过多的任务同时并发,原始的创建线程执行的方式已经不适合新的场景,后来引入了线程池来管理这些线程。处理的过程是将任务加到任务队列,然后让空闲的线程去执行,线程繁忙的时候让任务挂起,当连接池的数量不再是最大值时再执行
java里的几个类:
java线程池的顶级接口是Executor,本身是个线程池的接口。
1、ExecutorService:真正线程池的接口
2、ScheduleExecutorService:能和Timer/TimerTask类似,解决那些需要任务
重复执行的问题。
3、ThreadPoolExcutor:ExecutorService的默认实现。
4、ScheduleThreadPoolExcutor:继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。
使用:
Future future = executor.submit(Runnable runnable);
Future future = executor.submit(Callable callable);,返回的future有意义
Future future = executor.execute(Runnable runnable);返回的future没有意义
executor.shutdown();
总结:
在线程池内部,当前线程数小于核心线程数时,会自动开启核心线程执行任务。
超过核心线程池数量时,会交给任务队列去等待。等到空闲的线程。
但是当任务队列也满,但是小于最大线程数时,会立即开启非核心线程去执行。
最大的线程也满后,handler抛出RejectExecutionExpection异常。