进程:一个进程对应一个应用程序(每个进程都有独立的内存和资源)
线程:程序中的实际运作单位(一个程序中的线程共享其内存和资源,堆内存和方法内存共享,栈内存独立,一个线程一个栈)
1、(推荐)实现Runnable接口,重写run()方法(保留类的继承)
//MyClass实现Runnable接口,这里用到了静态代理
new Thread(new MyClass).start();
2、继承Thread类,重写run()方法
//也可以直接创建MyClass对象
Thread t = new MyClass();
t.start();
3、实现Callable接口
好处:可以返回结果,可以抛出异常
//实现Callable接口 重写call()方法 call()方法的返回值类型和实现类的泛型相同
//建立实现类的实例
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
MyClass mc3 = new MyClass();
//创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1 = ser.submit(mc1);
Future<Boolean> r2 = ser.submit(mc2);
Future<Boolean> r3 = ser.submit(mc3);
//获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
//关闭服务
ser.shutdownNow();
新建
new 表示新建状态
就绪
调用start()方法进入就绪状态
就绪状态的线程表示有权利去获取CPU的时间片。CPU时间片是执行权。当线程拿到CPU时间片之后就马上执行run()方法,这个时间就进入了运行状态。
运行
run方法运行
在运行状态时,如果此时CPU的时间到了,但是run()方法还没有执行完成,那么就回到就绪状态,等待线程获取CPU时间片,获取到CPU时间片后继续运行run()方法。以上过程是JVM在调度。
消亡
run()方法结束线程消亡
阻塞
如果run()运行时遇到阻塞事件就进入阻塞状态,阻塞解除就进入就绪状态
抢占式调度:(Java使用)优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取到的CPU时间片会相对多一些
分时调度: 所有线程轮流得到CPU的使用权,平均分配给每个线程CPU的时间片
1-10
其中
NORM_PRIORITY(标准)默认5
MAX_PRIORITY(最高级)10
MIN_PRIORITY(最低级)1
休眠,入参是毫秒时间。将该方法写在哪,哪的线程将休眠,即将该方法写在重写的run方法中,则run所在线程将休眠,如果写在main中,那么main将休眠
打断休眠(“t”是该线程),在其他位置使用 t.interrupt()方法,打断该线程,该线程的sleep()方法会抛出一个打断异常终止休眠,执行后续代码
终止一个线程,1,使用一个属性判断,然后修改属性终止。2,不推荐使用stop()等方法过时的方法
没有入参,让位给同优先级的其他线程,让位的时间不固定,大意和sleep方法相同
合并线程,如果 t.join(); 在main方法中,那么t 线程将于main线程合并,将以上代码都执行完毕后才执行join之后的代码,就变成了单线程
表示线程一直等待,直到其他线程通知,与sleep()不同,wait()会施放锁
指定等待的毫秒数
唤醒一个处于等待状态的线程
唤醒同一对象上所有调用wait()方法的线程,优先级高的线程优先调度
更改优先级
返回当前线程对象
返回此线程的名称
测试这个线程是否活着
is系列
是否是守护线程
是否被中断
设置当前线程为守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
当线程执行到该关键字修饰的代码时候,会去获取线程的锁,然后执行代码,执行结束后归还锁。这期间其他线程无法获取到该锁,所以会等待前面线程执行,即执行方式从多线程异步暂时变为了同步执行
推荐:synchronized(this) {“do something”} 将需要同步的代码框柱
synchronized修饰需要同步的方法
类锁,修饰在静态方法、静态变量上,可以对类加锁
类MyClass中有两个方法m1()和m2()
类Processor继承Thread并且构造器中需要传入一个MyClass对象
m1()和m2()都有synchronized修饰
建立两个线程
MyClass mc = new MyClass();
Processor p1 = new Processor(mc);
Processor p2 = new Processor(mc);
此时 p1执行m1()方法(死循环)
p2执行m2()方法
问: p2是否需要等待p1执行结束
答: 需要,p1和p2都是通过一个mc对象构造的,所以m1()和m2()方法是同一个对象 synchronized加了锁
建立两个线程
Processor p1 = new Processor(new MyClass());
Processor p2 = new Processor(new MyClass());
此时 p1执行m1()方法(死循环)
p2执行m2()方法
问: p2是否需要等待p1执行结束
答: 不需要,p1和p2是通过两个不同的对象构造的
m1()有static synchronized修饰
m2()只有有static修饰
建立两个线程
MyClass mc = new MyClass();
Processor p1 = new Processor(mc);
Processor p2 = new Processor(mc);
此时 p1执行m1()方法(死循环)
p2执行m2()方法
问: p2是否需要等待p1执行结束
答: 不需要,m2没有被synchronized修饰
上述的特殊情况一定要考虑好synchronized修饰的是对象锁还是类锁
对象锁: 不同线程共享同一个对象需要等待,不同享同一个对象不需要等待
类锁: 不同线程不同享同一个对象也需要等待
使用示例
private final ReentrantLock lock = new ReentrantLock();
public void m(){
lock.lock();
try{
//要保证线程安全的代码
}finally {
lock.unlock();
//如果同步代码有异常需要将unlock()写入finally
}
}
线程t1锁住o1对象,然后还要去锁o2对象
线程t2锁住o2对象,然后还要去锁o1对象
就形成了死锁,要避免死锁的发生
示例代码:
public static void main(String[] args) throws InterruptedException {
Object o1 = new Object();
Object o2 = new Object();
new Thread(() -> {
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "已锁o1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "已锁o2");
}
}
}).start();
Thread.sleep(1000);
new Thread(() -> {
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "已锁o2");
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "已锁o1");
}
}
}).start();
}
概念 线程分为用户线程和守护线程,只有当所有用户线程结束生命周期,守护线程才会结束。守护线程一般都无限循环
使用 setDaemon(Boolean b)方法
Executor: 工具类、线程池的工厂类,用于创建并返回不同类型的线程池
ExecutorService: 真正的线程池接口。常见子类ThreadPoolExecutor
常用方法:
coid execute(Runnable command) 执行任务/命令,没有返回值,一般用来执行Runnable
Futuresubmi(Callable task) 执行任务,有返回值,一般用来执行Callable
void shutdown() 关闭线程池
实现Runnable接口
//1、创建服务,创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2、关闭连接
service.shutdown();
实现Callable接口
//建立实现类的实例
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
MyClass mc3 = new MyClass();
//创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1 = ser.submit(mc1);
Future<Boolean> r2 = ser.submit(mc2);
Future<Boolean> r3 = ser.submit(mc3);
//获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
//关闭服务
ser.shutdownNow();