线程,进程,多线程
1.进程:每个应用程序都是一个进程
2.线程:每个进程至少包含一个线程,线程接受CPU的调度
Thread
package com.zwj.thread;
/**
* @author zwj
* @date 2022/2/18 - 11:03
*/
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyThread:"+i);
}
}
}
package com.zwj.thread;
/**
* @author zwj
* @date 2022/2/18 - 11:04
*/
public class Test {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("main:"+i);
}
}
}
Runnable
package com.zwj.runnable;
/**
* @author zwj
* @date 2022/2/18 - 11:07
*/
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyRunnable:"+i);
}
}
}
package com.zwj.runnable;
/**
* @author zwj
* @date 2022/2/18 - 11:08
*/
public class Test {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("main:"+i);
}
}
}
Callable
可以有返回值
package com.zwj.callable;
import java.util.concurrent.Callable;
/**
* @author zwj
* @date 2022/2/18 - 11:11
*/
public class MyCallable implements Callable<Boolean> {
private String name;
public MyCallable(String name) {
this.name = name;
}
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("MyCallable-"+name+":"+i);
}
return true;
}
}
package com.zwj.callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
/**
* @author zwj
* @date 2022/2/18 - 11:14
*/
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable m1 = new MyCallable("1");
MyCallable m2 = new MyCallable("2");
MyCallable m3 = new MyCallable("3");
//创建线程池
ExecutorService service = new ScheduledThreadPoolExecutor(3);
//提交线程
Future<Boolean> submit1 = service.submit(m1);
Future<Boolean> submit2 = service.submit(m2);
Future<Boolean> submit3 = service.submit(m3);
Boolean aBoolean = submit1.get();
Boolean aBoolean1 = submit2.get();
Boolean aBoolean2 = submit3.get();
//关闭线程池
service.shutdown();
}
}
线程状态
1.创建状态: new 线程
2.就绪状态: start()方法
3.阻塞状态: sleep()方法或者wait()方法或者同步锁,解除后才能重新被cpu调度
4.运行状态: 执行代码块
5.死亡状态: 线程中断或执行完毕
sleep和wait的区别
1.sleep方法来自Thread类,wait来自Object类
2.sleep方法不会释放锁,wait方法会释放所有锁
3.sleep方法阻塞到时间后会自动重新竞争cpu资源,wait需要等待其他线程调用notify/notifyAll方法唤醒线程
4.notify()随机唤醒一个线程,notifyAll()唤醒所有线程
5.sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
yield
礼让线程
让出当前占用的CPU资源,重新进入就绪状态竞争资源,有可能重新被选中,导致礼让不成功
join
线程插队
在其他线程启动前调用join方法,强制插队执行,直接抢夺CPU,执行完毕才释放资源
调用位置必须写好,只有在线程start后调用才有效果
package com.zwj.join;
/**
* @author zwj
* @date 2022/2/18 - 11:40
*/
public class JoinThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (Thread.currentThread().getName().equals("thread1")){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+i);
}
}
public static void main(String[] args) throws InterruptedException {
JoinThread joinThread = new JoinThread();
Thread thread1 = new Thread(joinThread,"thread1");
Thread thread2 = new Thread(joinThread,"thread2");
Thread thread3 = new Thread(joinThread,"thread3");
thread1.start();
thread1.join();
thread2.start();
thread3.start();
}
}
线程优先级
线程优先级并不能保证线程一定会优先执行,只是概率大了,因为最终的选择由CPU决定,无法认为参与
//设置线程优先级
thread.setPriority()
守护线程
1.虚拟机必须保证用户线程执行完毕,虚拟机不用等待守护线程执行完毕
2.如后台记录操作日志,垃圾回收,监控内存
线程同步(锁)
synchronised (排他锁) 同步方法和同步代码块
Lock锁:JDK1.5之后出现,显式同步锁 手动解锁 可重入锁
package com.zwj.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author zwj
* @date 2022/2/18 - 13:47
*/
public class MyLockThread implements Runnable{
//票
int ticketNum = 10;
//定义Lock锁
private final Lock lock = new ReentrantLock();
@Override
public void run() {
try {
lock.lock(); //加锁
while(ticketNum>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNum--);
}
}finally {
lock.unlock();
}
}
}
死锁 多个线程各自占用的资源都是对方想要的,导致僵持住,然后形成死锁,代码无法继续运行下去
形成死锁的四个条件:
1.互斥条件:一个资源一次只能被一个进程使用
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3.不剥夺条件:进程已获得的资源,在未使用完之前,不能被强行剥夺
4.循环等待资源:若干进程之间形成一种头尾相接的循环等待资源关系
线程通信
1.wait 和 notify notifyAll 进行线程通信,唤醒线程
2.使用基于线程安全的List做数据缓冲区
线程池
线程池七个参数:
1.corePoolSize: 核心池大小,核心线程不会被回收
2.maximumPoolSize: 最大线程数
3.keepAliveTime:空闲线程存活时间,线程超过空闲时间,会被回收只剩核心线程
4.unit:时间单位 keepAliveTime的时间单位
5.workQueue:工作队列,存放待执行任务的队列:当提交的任务数超过核心线程数大小后,再提交的任务就存放在工作队列,任务调度时再从队列中取出任务。它仅仅用来存放被execute()方法提交的Runnable任务,五种队列
6.threadFactory:线程工厂
7.handler:拒绝策略
1)丢弃抛异常
2)丢弃不抛异常
3)丢弃队列最前面的任务
4)由调用线程执行该任务