多线程
程序是指令和数据的有序集合,其本身没有运行的含义,是一个静态的概念。
进程则是执行程序得一次执行过程,是一个动态的概念。
通常一个进程中包含若干个线程,一个进程至少有一个线程,否则没有存在的意义。线程是CPU调度和执行得单位。
线程创建
Thread、Runnable、Callable
Thread
自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
public static void main(String[] args){
//创建线程对象
StartThread1 t = StartThread1();
t.start();
}
public class StartThread1 extends Thread{
//线程入口点
@Override
public void run() {
//线程体
}
}
Runnable
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
public class StartThread2 implements Runnable{
//线程入口点
@Override
public void run() {
//线程体
}
}
StartThread2 st = new StartThread2(); //创建实现类对象
Thread thread = new Thread(st); //创建代理类对象
thread.start(); //启动
推荐使用Runnable接口,避免继承局限性,灵活方便
Callable(了解即可)
-
实现Callable接口,需要返回值类型
-
重写call方法,需要抛出异常
-
创建目标对象
-
创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
-
提交执行:Future<Boolean> result1 = ser.submit(t1);
-
获取结果:boolean r1 = result1.get()
-
关闭服务:ser.shutdownNow();
静态代理
真实对象和代理对象实现统一接口
代理对象要代理真实角色
线程方法
setPriority(int newPriority) | 更改线程的优先级 |
---|---|
static void sleep(long millis) | 在指定毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程,不使用该方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
守护(daemon)线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
同步块
synchronized(Obj){ }
Obj称之为同步监视器
死锁
多个线程互相抱着对方需要的资源,形成僵持.
产生死锁的四个必要条件:
-
互斥条件:一个资源每次只能被一个进程使用。
-
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
-
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
-
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
Lock(锁)
class A{
private final ReentrantLock lock = new ReenTrantLock();
public void m(){
lock.lock();
try{
//保证线程安全的代码;
}
finally{
lock.unlock();
}
}
}
线程池
背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
-
提高响应速度(减少了创建新线程的时间)
-
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
-
便于线程管理