进程概述
正在运行的程序就是进程
单线程不会出现安全问题,但是效率堪忧
- 分时调度:每个线程平均占用CPU
- 抢占调度:优先级不同的线程可以
Thread子类实现线程
- 继承至Thread类,并重写Thread方法的run()
- 将要执行的代码放到run()中
- 创建子类对象,调用start(),多次开启线程是不合法的
- 执行具有随机性
问什么要继承Thread类:
因为Thread类是线程类,继承至Thread的类,可以为写在run()的代码块提供一个模板。所以run是提供要运行的代码,start()才是开启线程。
线程的内存:
内存会在开辟一个栈区,然后让run()进入到这个栈。栈内存都是线程私有的
Thread方法
public String getName():这是Thread的方法,并不是子类的方法
public static Thread currentThread()
public void setName(String name)用子类对象去调用这个方法
public void sleep(long second)
==这个方法不能抛出异常,因为父类Thread不能抛出,所以子类也不能抛==
Runnable
- 实现了Runnable接口的类
- 覆盖run方法
- 创建Thread类对象
- 构造方法传递实现类,传递Runnable的接口实现类
- 调用strat()
public subRunnable implements Runnable{
public void run(){
}
}
public static void main(String[] args){
SubRunnable sr = new SubRunnable();
Thread th = new Thread(sr);
th.start();
}
- 接口解决了单继承的局限性
- 将任务对象,和线程对象分离
匿名内部类实现多线程
//匿名内部类是没有子类的
//继承方式 xxxclass extends Thread{public void run()}
//直接new Thread,这个匿名内部类就是Thread的子类
new Thread(){
public void run(){
}.start();
}
//匿名内部类实现类接口引用
Runnable r = new Runnable(){
public void run(){
};
new Thread(r).start;
}
new Thread(new Runnable(){
public void run(){
}
}).start();
线程池原理
线程池就是用来存储线程的容器,当线程没又试用的时候就会将线程回收但是不关闭线程,可以重复使用这个线程,节省掉反复创建销毁线程的内存开销。sun公司在JKD1.5之后就提供了线程池的API
线程池这个容器都是由线程工厂
生产的
|--Utils
|--Executors
public static ExecutorService newFixedThreadPool(int nThreads)
ExecutorService:线程池接口
Future<?> submit(Runnable task)
Future<?> submit(Callable<?> task)
返回的是接口其实是说返回的是这个接口的实现类ThreadPoolExecutor,让这个类去实现run
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new Runnable());
es.shutdown();
//关闭线程池
Callable
Runnable
接口存在的问题:
- run 方法是void的
- 不能排除异常
- 可以用Callable<V>接口来解决,其使用的方式和Runnable一样
- 重写Callable的call()
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new Callable<?>());
//拿到返回值的方式Futere接口
Future<T> f = es.submit(new Callable<T>());
es.shutdown();
//关闭线程池
多线程异步计算实例
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(task);
es.submit(task);
//可以往构造器里面传入参数