当前位置:网站首页>线程介绍与使用
线程介绍与使用
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
九、线程按顺序执行
边栏推荐
猜你喜欢
随机推荐
HCIP练习(OSPF)
Redis的基础与django使用redis
WPS EXCEL 筛选指定长度的文本 内容 字符串
ArcEngine(五)用ICommand接口实现放大缩小
“唯一索引允许为空“ 的说法是不严谨的
HCIP练习02(OSPF)
如何使用电子邮件营销在五个步骤中增加产品评论
2022下半年软考「高项&集成」复习计划ta来喽~
Shell运维开发基础(一)
MySQL or使索引失效
ArcEngine (4) Use of MapControl_OnMouseDown
WordPress主题-B2美化通用子主题商业运营版
mysql存生僻字奇怪问题,mysql为什么不能辨别mb4字符?
推荐系统-排序层-模型:Wide&Deep
集群
sqlite 日期字段加一天
AI mid-stage sequence labeling task: three data set construction process records
ArcEngine (1) Loading vector data
ArcEngine(六)用tool工具实现拉框放大缩小和平移
循环神经网络RNN基础《PyTorch深度学习实践》