当前位置:网站首页>线程介绍与使用
线程介绍与使用
2022-08-03 08:11:00 【一梦无痕bzy】
一、进程和线程区别
1、进程:cpu分配资源的基本单位。可以把一个个单独的程序看成进程,进程与进程之间不共享内存,若想交互需要通过TCP/IP端口
2、线程:cpu执行的基本单位(cpu同一时间只能执行一个线程)。可以看成是进程中一个个正在运行的东西,隶属于进程,线程之间可以交互,因为他们都指向同一个进程的内存
二、线程开辟
1、继承Thread类,重写run方法,new出用start启动
package com.example.demo.thread;
public class MyThread extends Thread{
public void run(){
System.out.println("test");
}
public static void main(String[] args) {
MyThread mt = new MyThread();
//1、需要调用start方法使线程启动
//2、start方法会开启一个新的线程,来执行run中的逻辑
//3、直接调用run方法则不会产生新的线程,依然在主线程中按顺序执行
mt.start();
}
}
2、实现Runnable接口,重写run方法,new出用start启动
代码如上,用的比较多,因为继承是单继承,而实现可以多实现
3、实现Callable接口:可以定义返回值、可以抛出异常
package com.example.demo.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MyThread2 implements Callable<String> {
@Override
public String call() throws Exception {
return "ok";
}
public static void main(String[] args) throws Exception{
//1、创建一个线程池
//调用Executors类的静态方法
ExecutorService service = Executors.newFixedThreadPool(10);
//2、提交执行
Future<String> submit1 = service.submit(new MyThread2());
Future<String> submit2 = service.submit(new MyThread2());
//3、获取结果
String s1 = submit1.get();
String s2 = submit2.get();
System.out.println(s1+";"+s2);
//4 关闭线程池
service.shutdown();
}
}
Runnable和Callable比较
1、callable的核心是call方法,允许返回值,runnable的核心是run方法,没有返回值
2、call方法可以抛出异常,但是run方法不行
3、callable和runnable都可以应用于executors。而thread类只支持runnable
三、线程生命状态
1、new
2、Runable(ready、running):.start进入ready,被线程调度器选中获得cpu资源变为running。处于running状态的线程被挂起或yield变成ready
3、timewaiting:Threed.sleep(time)、o.wait(time)、t.join(time)
4、waiting:o.wait、t.join
5、blocked(阻塞):没抢到锁,进入等待队列
6、teminated:结束或抛异常
1、线程被挂起指的是,cpu同一时间只能执行一个线程,然后来回切换执行,当cpu执行一个其余处于没被执行状态的线程就是被挂起,回到就绪态
2、intermpt是一个用来终止处于阻塞状态线程的方法,用了它之后会抛出异常捕获处理便可(但一般在开发过程中不会去使用它,只有特别底层架构才去使用它,比如netty)。stop是一个被抛弃的方法。最好的终止线程的方法就是让它自己结束,其次用标志位
四、Thread类
1、线程命名、查看线程状态、设置守护线程
package com.example.demo.thread;
public class MyThread extends Thread{
public void run(){
System.out.println("test");
}
public static void main(String[] args) {
MyThread mt = new MyThread();
//为线程设置名字为t1。这行代码的意思是:mt就相当于是一个任务,把这个任务交给线程t1了
Thread t1 = new Thread(mt,"t1");
//true设置为守护线程、false用户线程。默认false
// t1.setDaemon(true);
System.out.println(t1.getState().name());
t1.start();
System.out.println(t1.getState().name());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t1.getState().name());
}
}
这种模式为静态代理模式,代理者可以把原对象所做的事都做了,而且还能做它所不能做的事。实现方式是代理类引入被代理类,代理类构造方法传被代理对象,代理方法中调被代理类的方法,这样被代理类要做的事都被代理类做了。而且还可以再此基础上改善代理方法、代理类,进而做到更多的事。比如:
getState():获取线程当前所处状态
setDaemon(true/false):true设置为守护线程、false用户线程。默认false
2、线程休眠:sleep
Thread.sleep():参数是毫秒。在哪个线程中就让哪个线程休眠
3、线程礼让:yield
指的是让正处于运行态的线程释放自己的cpu资源,变回就绪态继续和其他线程抢夺cpu时间片
package com.example.demo.thread;
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
if (i == 3) {
Thread.yield();
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread(),"t1");
Thread t2 = new Thread(new MyThread(),"t2");
t1.start();
t2.start();
}
}
4、设置优先级:setPriority
只是设置了线程抢到cpu时间片的概率并不是一定优先执行,优先级的设定是一个0到10的整数,默认是5,大的可能优先执行
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread(),"t1");
Thread t2 = new Thread(new MyThread(),"t2");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
5、线程插队:join
其他线程进入等待状态,待此线程执行完后,进入就绪态。可保证线程按照指定的顺序执行
package com.example.demo.thread;
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("vip线程来了:" + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyThread(), "t1");
t1.start();
//主线程
for (int i = 0; i < 20; i++) {
if (i == 5) {
t1.join();
}
System.out.println("main:" + i);
}
}
}
线程插队可以真正的保证线程执行的顺序。比如有1、2、3三个线程,在3中join2、2中join1,就可以保证一定是先执行1然后2最后3
五、线程等待
让线程等待其他线程执行完再去执行
1、Object的wait、notify、notifyall,主要与synchornized配合使用
wait:等待。是Object类中的一个方法,当前线程释放自己的锁标记,并且让出cpu资源,使得当前的线程进入等待队列
notify:通知。是Object类中的一个方法,唤醒等待队列中的第一个线程,使这个线程进入锁池(跟线程优先级无关)
notifyall:通知。是Object类中的一个方法,唤醒等待队列中的所有线程,使这些线程进入锁池
public static void main(String[] args) throws InterruptedException {
Runnable runnable1 = () -> {
synchronized ("A"){
System.out.println("A线程持有了A锁,等待B锁");
//释放已持有的A锁标记,进入等待队列
try {
"A".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized ("B"){
System.out.println("A线程同时持有了A锁和B锁");
}
}
};
Runnable runnable2 = () -> {
synchronized ("B"){
System.out.println("B线程持有了B锁,等待A锁");
synchronized ("A"){
System.out.println("B线程同时持有了A锁和B锁");
"A".notifyAll();
}
}
};
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
}
2、Condition的await、signal、signalAll,主要与ReentrantLock配合使用
与上面三个方法一一对应,可以看成是上面三个方法的升级
具体使用方法会在讲解ReentrantLock时详细介绍
3、CountDownLatch
4、CyclicBarrier
六、线程停止
最好是让线程自己正常运行结束停止、其次利用标志位、不要用stop或者destroy等过时方法
标志位方式
package com.example.demo.thread;
public class MyThread implements Runnable {
//定义线程体使用的标识
private boolean flag = true;
@Override
public void run() {
//线程体使用该标识
while (flag){
System.out.println("线程执行");
}
}
//对外提供方法改变标识
public void stop(){
this.flag = false;
}
}
七、线程限流:Semaphore
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
for (int index = 0; index < 20; index++) {
final int Num = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing: " + Num);
//模拟实际业务逻辑
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放
semp.release();
} catch (InterruptedException e) {
}
}
};
// 放入线程池并执行
exec.execute(run);
}
Thread.sleep(10);
// 退出线程池
exec.shutdown();
}
八、线程存储数据:ThreadLocal
九、线程按顺序执行
边栏推荐
猜你喜欢
随机推荐
五、《图解HTTP》报文首部和HTTP缓存
最佳高质量字体
WPF 学习笔记《WPF样式基础》
【TPC-DS】DF的SQL(Data Maintenance部分)
【愚公系列】2022年07月 Go教学课程 026-结构体
判断根节点是否等于子节点之和
vs 2022无法安装 vc_runtimeMinmum_x86错误
Redis的基础与django使用redis
AI中台序列标注任务:三个数据集构造过程记录
ArcEngine(一)加载矢量数据
流行和声基础大笔记
ArcEngine (5) use the ICommand interface to achieve zoom in and zoom out
Charles抓包工具学习记录
分析型数据库性能测试总结
rust 学习笔记
Gauva的ListenableFuture
【论文笔记】一种基于启发式奖赏函数的分层强化学习方法
mysql备份时的快照原理
NFT到底有哪些实际用途?
How does Mysql query two data tables for the same fields in two tables at the same time