多线程
文章目录
1、普通方法调用和多线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-waDlYlZJ-1603975644100)(E:\桌面\images\1603728306(1)].png)
- 进程是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位
- 通常在 一个进程中可以包含若干个线程,一个进程中至少有两个线程(Main,GC)。线程是CPU调度和执行的单位
很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
-
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
-
线程会带来额外的开销,如cpu调度时间,并发控制开销
-
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
2、三种创建方式
Thread class – 继承Thread类
Runnable接口 – 实现Runnable接口
Callable接口 – 实现Callable接口
一般使用Runnable,java单继承多接口
API
Thread.currentThread().getName();
Thread.sleep();
2.1、Thread
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
线程开启不一定执行,由cpu调度执行
class MyThread extends Thread{
public void run (){}
}
class Test{
psvm{
MyThread my = new MyThread();
my.run();
}
}
2.2、Runnable
- 定义类实现Runnable接口
- 实现run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
class MyRunnable implements Runnable{
public void run (){}
}
class Test{
psvm{
MyRunnable my = new MyRunnable();
Thread thread = new Thread(my);
thread.run();
// new Thread(new MyRunnable()).run();
}
}
2.3、Callable
-
实现Callable接口,需要返回值类型
-
重写call方法,需要抛出异常
-
创建目标对象t1
-
创建执行服务:ExecutorService ser =Executors.newFixedThreadPool(1);
-
提交执行:Future result =ser.submit(t1);
-
获取结果:boolean r1=result.get();
-
关闭服务:ser.shutdownNow();
3、Lambda表达式
函数式接口:接口只包含唯一一个抽象方法
4、线程状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gAwDhQGc-1603975644103)(E:\桌面\images\1603777623(1)].png)
public enum State{
//新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待,死死地等
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}
5、线程方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级1~10,MIN_PRIORITY=1,MAX_PRIORITY=10,NORM_PRIORITY=5,setPriority(int); |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止,再执行其他线程,其他线程阻塞 |
static void yield() | 暂停当前正在执行的线程对象,但不阻塞,并执行其他线程。礼让线程,将线程从运行状态转为就绪状态。让cpu重新调度,礼让不太一定成功,看cpu |
void interrupt() | 中断线程,不用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
6、守护线程
线程分为用户线程和守护线程(Deamon)
守护线程:
setDeamon(true); //默认false表示用户线程
7、线程同步
锁机制:synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可
synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。
8、同步方法和同步代码块
同步方法:
public synchronized void test(){}
同步块:
synchronized(Obj){}
9、死锁
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥有两个以上对象的锁时,就可能会发生死锁的问题
多个线程互相抱着对方需要的资源,然后形成僵持。
产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
只要破坏其中的任意一个或多个条件就可以避免死锁的产生
10、Lock锁
可重入锁ReentrantLock
private final ReentrantLock lock =new ReentrantLock();
lock.lock();
lock.unlock();
lock.tryLock();
11、线程池
ExecutorService:线程池接口,常见子类ThreadPoolExecutor
- void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
- Future sumbit(Callable task):执行任务,有返回值,一般用来执行Callable
- void shutdown():关闭连接池
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池