java 线程是很重要的一项,所以作为 java 程序员必须要掌握的。
理解 java 线程必须先理解线程在 java 中的生命周期。、
1.java 线程生命周期
1.new 创建一个线程 java 中创建线程有三种方式,1. 继承 Thread 类,2. 继承 Runnable 接口,然后重写父类的 run 方法。
2.Runnable 线程处于就绪状态,随时可以被 cpu 调用。
3.Running 线程处于运行状态,此时线程正在 CPU 中执行。
4.Blocked 线程处于阻塞状态,由于某种原因,cpu 暂时中断线程的资源。只有线程再次进入就绪状态才能重新被 cpu 调用,同时阻塞有三种状态
(1)等待阻塞:运行状态中的线程执行 wait 方法,使本线程进入等待阻塞状态。
(2)同步阻塞:线程在获取 synchronized 同步锁失败 (因为锁被其它线程所占用),它会进入同步阻塞状态;
(3)其他阻塞:通过调用线程的 sleep() 或 join() 或发出了 I/O 请求时,线程会进入到阻塞状态。当 sleep() 状态超时、join() 等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入就绪状态。
(4)死亡状态:线程运行完毕或因异常终止线程,该线程结束生命周期。
2. 线程的三种创建方式
(1) 继承 Thread 类
- public class MyThread extends Thread{
- public MyThread(String name){
- super(name);
- }
- @Override
- public void run() {
- for(int i=0;i<100;i++)
- System.out.println(Thread.currentThread().getName()+" "+i);
- }
- }
(2) 继承 Runnable 接口
- public class MyRunnable implements Runnable{
- private boolean stop=false;
- @Override
- public void run() {
- for(int i=0;i<100&&!stop;i++){
- System.out.println(Thread.currentThread().getName()+" "+i);
- }
- }
- public void stopThread(){
- this.stop=true;
- }
- }
二者的区别在于 Thread 继承 Runnable 类,然后再继承 Thread 类从而调用线程,而 Runnable 类是一个接口,通过直接继承 Runnable 类来实现。
同时二者在创建时还有区别
测试 Thread:
- public void testThread() {
- for (int i = 0; i < 100; i++) {
- System.out.println(Thread.currentThread().getName() + " " + i);
- if (i == 30) {
- MyThread myThread1 = new MyThread("窗口1");
- MyThread myThread2 = new MyThread("窗口2");
- MyThread myThread3 = new MyThread("窗口3");
- MyThread myThread4 = new MyThread("窗口4");
- myThread1.start();
- myThread2.start();
- myThread3.start();
- myThread4.start();
- }
- }
- }
测试 Runnable 方式:
- public void testRunnable() {
- int i = 0;
- for (i = 0; i <= 100; i++) {
- System.out.println(Thread.currentThread().getName() + " " + i);
- if (i == 30) {
- Runnable myRunnable = new MyRunnable();
- Thread thread1 = new Thread(myRunnable);
- Thread thread2 = new Thread(myRunnable);
- thread1.start();
- thread2.start();
- }
- }
- }
可以看出来在继承 Thread 类后通过 new 一个继承了 Thread 的 MyThread 类来实现线程的创建,然后通过调用 Thread 方法中的 start()方法使线程处于就绪状态。
而继承了 Runnable 方法的类 new 一个 MyRunnable 然后在将 myRunnable 放入 new 的一个 Thread 中,然后在通过 start()方法使线程处于就绪状态。
3. 继承 Callable 类
- public class MyCallable implements Callable<Integer> {
- private int i=0;
- @Override
- public Integer call() throws Exception {
- int sum=0;
- for(;i<100;i++){
- System.out.println(Thread.currentThread().getName()+" "+i);
- sum+=i;
- }
- return sum;
- }
- }
测试:
- public void testCallable() {
- Callable<Integer> myCallable = new MyCallable();
- FutureTask<Integer> ft = new FutureTask<>(myCallable);
- for (int i = 0; i <= 100; i++) {
- System.out.println(Thread.currentThread().getName() + " " + i);
- if (i == 30) {
- Thread thread = new Thread(ft);
- thread.start();
- }
- }
- System.out.println("主线程执行完毕");
- try {
- int sum = ft.get();
- System.out.println("sum= " + sum);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
通过测试你会发现继承了 Callable 类之后会通过 FutureTask 类进行包装,然后再在 Thread 中调用,查 api 你会看到 FutureTask 类既继承了 Future 类又继承了 Runnabl 类,同时 Callabl 类与另外两个的区别在于 call 方法有返回参数。
来源: http://www.cnblogs.com/smallbrokenchildwen/p/7096337.html