进程:程序执行后就会产生一个进程,程序运行的一个实例。
线程: 线程是进程内部的 。线程就是指令流,一条一条指令构成。
线程是jvm进行cpu调度的最小单位,而进程是jvm进行资源分配的最小单位。一个进程里可以有多个线程。
线程创建方式
1 直接用Thread创建
Thread t1 = new Thread(){ @Override public void run(){ } }; t1.start();
2 用runnable创建
Runnable task = new Runnable(){ @Override public void run(){ } }; Thread t1 = new Thread(task); t1.start();
3用FutureTask 配合Thread
FutureTask t = new FutureTask(new Callable<Integer>(){ //任务代码 @Override public Integer call(){ return new Integer(1); } }); Thread t1 = new Thread(t); t1.start(); t.get();
FutureTask 在创建时需要传一个实现Callable接口的参数。这个接口中有个call方法,就是我们需要写的执行代码
FutureTask类有一个get方法。能得到线程执行后返回结果。
4利用lambda表达式创建线程
Runnable r = ()->{ //执行代码 }; Thread t1 = new Thread(r);
lambda表达式适用函数式接口(接口中只有一个方法需要实现)
Thread类本身就实现了Runable接口,所以最后都是调用Thread类中的run方法。
线程上下文切换
当一个线程的cpu时间片被用完后需要保存这个线程的执行状态和数据。 然后恢复其他线程的执行状态和数据。执行其他线程。然后等待该线程再次获得cpu时间片时。恢复状态继续运行。就是线程上下文切换。上下文切换比较耗费性能。所以线程不是越多越好。
线程相关api
start() 和 run()
start开启一个线程执行。
run 如果直接掉用run方法则不会开启线程,只是普通的方法调用
sleep()
让线程从running进入timed_waiting状态。线程会放弃cpu
其他线程可以调用interrupt方法打断sleep中的线程,并不会改变其interrupt标记,被打断的线程会抛出interruptException异常
睡眠结束后的进程也得等待cpu分配给他才能执行。进入就绪状态。
可以防止while(true)空转沾满整个cpu。在循环中添加thread.sleep
yield()
主动让出cpu,进入就绪状态。但是可能还会抢到cpu ,具体要看cpu分给谁。
TimeUtil.Second.sleep()
也可以达到和Thead.sleep一样的效果,内部也是调用thread.sleep只不过进行了单位换算。
线程优先级
setpriority() 没什么特别用处。主要还是得看cpu分给谁
join()
用来等待执行的线程结束
在主线程中调用t1.join就是主线程等待t1线程运行结束。
t1.join(long n) 最多等待n毫秒。如果超时了,就不等待了,当前线程继续向下运行
interrupt()
线程都有一个打断标记,表示这个线程是否被打断过。可以调用Thread.isinterrupted()看看打断标记是true还是false
打断 sleep wait join 进行等待的线程,打断后不会改变其 打断标记
本质打断阻塞的线程。sleep wait join 都是阻塞状态。这三个方式进入的阻塞状态被打断后,会把打断标记变为假。
如果打断的是正常的线程或者是park的线程,是会改变其打断标记为true
打断标记变为真后,再想park线程是停不下来的。
locksupport.park()
如果想再次把打断标记设置为假,那么我们可以调用Thread.interrupted()这个方法会返回当前打断标记,并且把打断标记设置为假。
对于正常运行的线程,被打断后,打断标记会变为真。
守护线程
只要其他非守护线程全部运行结束。 那么无论守护线程是否运行结束都会强制结束。
t1.setDaemon(true)
垃圾回收器就是一种守护线程。
线程状态
初始状态。创建了线程对象。
可运行状态。就是就绪状态。可以运行,只要分配到cpu就运行
运行状态。正在运行,当cpu时间片用完,进入可运行状态,等待下一次cpu分配,会导致线程上下文切换。
阻塞状态。
终止状态。线程运行结束。
根据Thread.state中,将线程分为六种状态
new。线程刚刚被创建还没有调用start()。
Runnable。包含了上面五种状态的。可运行状态,运行状态,阻塞状态。在java里无法区分这三种状态,都是runnable
blocked waiting timedwaiting都是java层面对于阻塞状态的不同划分。
在java中阻塞状态有3种 blocked waiting time_waiting
sleep 会导致 timed_waiting 有时间的等待就是timedwaiting
join 导致 waiting 没有时间的等待就是waiting
如果是synchronized锁导致的是blockd 等待锁的就是blockd