先复习一下线程的东西;
Java线程的内存模型
主内存与工作内存
-
所有的变量都在主内存,Java堆(线程共享)
-
每条线程都有自己的工作内存,虚拟机栈的部分区域(线程私有)
-
线程的工作内存保存了该线程使用到的变量的主内存副本,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存的变量
内存间的交互操作
交互:即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存的实现细节。
内存交互的操作,是所有线程问题的根源
Java内存模型定义了八种方法来实现这个细节。
-
必须保证下面的操作都是原子性的、不可再分的。
1:lock:把主内存变量标识为一条线程独占,此时不允许其他线程对此变量进行读写。
2:unlock:解锁一个主内存变量。
3:read:把一个主内存变量值读入到线程的工作内存,强调的是读入这个过程。
4:load:把read到变量值保存到线程工作内存中作为变量副本,强调的是读入的值的保存过程。
5:use:线程执行期间,把工作内存中的变量值传给字节码执行引擎。
6:assign(赋值):字节码执行引擎把运算结果传回工作内存,赋值给工作内存中的结果变量。
7:store:把工作内存中的变量值传送到主内存,强调传送的过程。
8:write:把store传送进来的变量值写入主内存的变量中,强调保存的过程。
线程状态
其中状态:
-
New:新建状态,线程中的任务代码还没有开始运行
-
Runnable:就绪状态(可执行状态)。新建线程调用start()方法,此时线程就处于就绪状态
处于就绪状态的线程,并不一定立刻执行run方法,还需要同其他就绪线程竞争CPU,由Java的线程调度程序来调度执行线程。
-
Running:线程获得CPU使用权,开始执行run方法
-
正在运行的线程,如果调用yield()方法,则强制进入Runnable就绪状态
-
-
Blocked:阻塞状态。几种进入阻塞的情况:
-
sleep方法:释放CPU,不释放锁。
-
join方法:A线程内调用B.join(),则串行执行,B线程先执行,A线程阻塞,底层是wait,并且释放锁。当B线程执行完毕,A线程继续执行。
-
等待用户输入
当sleep结束,join中断,或者用户输入(I/O完成),则线程进入Runnable就绪状态
-
-
Wating:等待队列。
-
此线程调用了wati()方法,释放CPU,释放锁,进入等待队列。
-
当其他线程调用notify()、notifyAll()方法,可以唤醒等待队列中的线程,进入锁池队列。
-
-
锁池队列:如果此线程获取锁失败,则进入锁池队列,等待拿锁线程释放锁。
-
线程挂起:一种主动行为,需要主动resume()进行恢复。不释放CPU
-
死亡状态:线程run方法结束,或因异常退出run方法。线程生命周期结束。
实现线程的方法
-
实现Callable接口
执行call方法之后,可以获取一个Future对象,此对象调用get方法,即可获得返回的Object。
此get方法阻塞,如果没有返回结果,就会阻塞;
-
实现Runnable接口(对任务的抽象)
-
继承Thread类(对线程的抽象)
// 继承Thread——对Thread类的抽象 public class MyThread extends Thread { @Override public void run() { super.run(); System.out.println("继承Thread"); } } // 实现Runnable接口——对任务的抽象 public class MyRunnable implements Runnable { @Override public void run() { System.out.println("实现Runnable接口"); } } // 实现Callable接口——有返回值的任务 public class MyCallable implements Callable { @Override public String call() throws Exception { return "实现Callable接口"; } public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); MyRunnable myRunnable = new MyRunnable(); Thread t2 = new Thread(myRunnable); t2.start(); MyCallable t3 = new MyCallable(); try { String res = t3.call(); System.out.println(res); } catch (Exception e) { e.printStackTrace(); } } }