2020-06-07

[TOC]

进程和线程的区别

  • 进程:每个进程都有独立的代码和数据空间,进程间的切换会有较大的开销,一个进程可以包含n个线程(进程是资源分配的最小单元)
  • 线程:同一类线程共享代码和数据空间,每个线程都有独立的运行栈和程序计数器,线程切换开销小(线程是cpu调度的最小单元)

开启线程的三种方式

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口
public class CallableThreadTest implements Callable {

    public static void main(String[] args) {
        CallableThreadTest callableThreadTest = new CallableThreadTest();
        FutureTask futureTask = new FutureTask<>(callableThreadTest);

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);
            if (i == 20) {
                new Thread(futureTask, "有返回值的线程").start();
            }
        }
        try {
            System.out.println("子线程的返回值:" + futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

    @Override
    public Integer call() throws Exception {
        {
            int i = 0;
            for (; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
            return i;
        }
    }
}

//Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实际在就是在操作系统中启动了一个进程。

线程状态转换

thread.png
  1. 初始状态:新建线程对象
  2. 就绪状态:调用start()方法,等待获取cpu的使用权
  3. 运行状态:就绪状态获取cpu,执行程序代码
  4. 阻塞状态:线程因为某些原因放弃cpu的使用权,暂时停止运行,直到线程进入就绪状态,才有机会转到运行状态,
  5. 死亡状态:线程执行完毕,或者因异常退出run()方法,该线程结束生命周期

Thread.sleep()

使线程进入阻塞状态,等待sleep超时则进入就绪状态,而后等待cup资源恢复到运行状态,睡眠期间并不会释放所持有的对象锁,被其他对象调用它的interrupt()方法会产生InterruptExceptin异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有 finally语句块)以及以后的代码 。

thread.join()

thread.join()方法只会使主线程进入等待池并等待t线程执行完毕后才会被唤醒。并不影响同一时刻处在运行状态的其他线程

class Thread1 extends Thread {
    private String name;

    public Thread1(String name) {
        super(name);
        this.name = name;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程" + name + "运行 : " + i);
            try {
                sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
    }

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "主线程运行开始!");
        Thread1 mTh1 = new Thread1("A");
        Thread1 mTh2 = new Thread1("B");
        mTh1.start();
        mTh2.start();

        try {
            mTh2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "主线程运行结束!");
    }
}
//       main主线程运行开始!
//        A 线程运行开始!
//        B 线程运行开始!
//        子线程A运行 : 0
//        子线程B运行 : 0
//        子线程A运行 : 1
//        子线程B运行 : 1
//        子线程A运行 : 2
//        子线程B运行 : 2
//        子线程B运行 : 3
//        子线程A运行 : 3
//        子线程B运行 : 4
//        B 线程运行结束!
//        子线程A运行 : 4
//        main主线程运行结束!
//        A 线程运行结束!

你可能感兴趣的:(2020-06-07)