印象笔记地址:https://app
线程和进程专题
进程是资源分配的基本单位,线程是调度的基本单位。
线程依赖于进程,不能独立存在。
创建线程的4种方式总结:
1.创建线程的第一种方式:继承Thread类
(1)创建一个类继承Thread类,重写run()方法,将所要完成的任务代码写进run()方法中;
(2)创建Thread类的子类的对象;
(3)调用该对象的start()方法,该start()方法表示先开启线程,然后调用run()方法;
注意:不是创建了线程.start()就直接运行,而是 要等待时间片轮转
2.创建线程的第二种方式:实现Runable接口
(1)创建一个类并实现Runnable接口
(2)重写run()方法,将所要完成的任务代码写进run()方法中
(3)创建实现Runnable接口的类的对象,将该对象当做Thread类的构造方法中的参数传进去
(4)使用Thread类的构造方法创建一个对象,并调用start()方法即可运行该线程
3.创建线程的第三种方式:实现Callable接口
(1)创建一个类并实现Callable接口
(2)重写call()方法,将所要完成的任务的代码写进call()方法中,需要注意的是call()方法有返回值,并且可以抛出异常
(3)如果想要获取运行该线程后的返回值,需要创建Future接口的实现类的对象,即FutureTask类的对象,调用该对象的get()方法可获取call()方法的返回值
(4)使用Thread类的有参构造器创建对象,将FutureTask类的对象当做参数传进去,然后调用start()方法开启并运行该线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ExecutorService es = Executors.newFixedThreadPool(3); Callable<Integer> task1 = new MyTask1(); Callable<Integer> task2 = new MyTask2(); Future<Integer> f1 = es.submit(task1); Future<Integer> f2 = es.submit(task2); Integer result1 = f1.get(); Integer result2 = f2.get(); System.out.println(result1 +result2); } class MyTask1 implements Callable<Integer> { @Override public Integer call() throws Exception { Integer sum = 0; for (int i = 1; i <= 50; i++) { sum += i; } return sum: } |
4.创建线程的第4种方式:通过线程池
(1)使用Executors类中的newFixedThreadPool(int num)方法创建一个线程数量为num的线程池
(2)调用线程池中的execute()方法执行由实现Runnable接口创建的线程;调用submit()方法执行由实现Callable接口创建的线程
(3)调用线程池中的shutdown()方法关闭线程池
常用的接口:
- Excutor(java.util.concurrent包下):线程池的顶级接口
- ExcutorService:线程池接口,继承了Excutor接口 可通过submi t (Runnable task) 提交任务代码。
- Excutors:线程池工具类,工厂类,可用于生成线程池对象
线程的基本状态:
阻塞状态:等待某个监视器所标记的状态
无限期等待状态:无限期地等待另一个线程来执行某一 特定操作的线程处于 这种状态(等待唤醒)。
sleep方法与wait方法的区别,带时间参数时有什么区别?
sleep()是线程的静态方法,但它并不释放对象锁。
wait()方法使当前线程暂停执行并释放对象锁标志,让其他线程可以进入Synchronized数据块,当前线程被放入对象等待池中。