线程—并发编程(基础+2)
文章目录
一、线程之间的相互控制
提示:这一部分是接着上一篇继续展开的哈哈哈:
1、Thread.yield()方法
线程让步:使用该方法的线程从运行态切换到就就绪状态(只是放弃了CPU,没有等待外部条件),此时该线程随时可以被调度回CPU。
举个例子看一下吧👇👇👇👇👇👇
public class MethodYield {
public static void main(String[] args) {
PrintWhoAmI why=new PrintWhoAmI("魏神么");
PrintWhoAmI eat=new PrintWhoAmI("不吃饭");
why.start();
eat.start();
}
}
class PrintWhoAmI extends Thread{
public String name;
PrintWhoAmI(String name){
this.name=name;
}
@Override
public void run() {
while(true){
System.out.println("本小姐是"+name);
// if(name.equals("魏神么")){
// Thread.yield();
// }
}
}
}
此时,who和eat两个线程并发执行,输出内容的概率和频率大致相等,但是,加上yield()方法之后(就是上面代码中注释掉的那几条语句),why线程调用yield()方法,所以该线程做出让步,主动放弃CPU,“魏神么”的输出次数远远小于“不吃饭”。
那么,什么时候会用到yield()方法呢?
yield()方法主要用于执行一些耗时较久的计算任务,为了防止计算机处于“卡顿”的现象,时不时的让出CPU这个宝贵资源,给操作系统的其他进程用(来干点别的活儿)。
2、停止线程的相关方法
B线程正在赶别的事,但发生了一些突发情况,A线程需要叫B线程来帮他干点别的事儿,此时A线程就需要通知B线程停下来手头正在忙的事情来帮助他。
(1)Thread.stop()方法
暴力法停止,不管被停止的线程工作到了哪一步,直接干掉希望停止的线程。但是这种方法太暴力了,所以这个方法就不咋用了。
(2)Thread.interrupt()方法
一种优雅的方式来停止希望停止的线程。要停止B线程,就与B线程进行协商,比较温柔。众所周知,interrupt是中断的意思,实际上并不会影响B线程的运行,而是给B线程发送一个消息(设置了一个停止标志)。那么问题来了,B线程是怎么感知到有人让他停止呢?
分情况讨论:
- B线程处于运行状态:可以通过 interrupted() 方法来判断是否有人让他停止。返回true:有人让他停止;返回false:没人让他停止。(至于B要不要停止,完全是代码控制的)
- B线程处于休眠状态(sleep,join……):这就意味着B无法立即执行 interrupted() 方法,此时JVM的处理方式是以异常形式通知B(InterruptedException)。当B处于休眠状态时,捕获了 InterruptedException 异常,代表有人让B线程停止,具体要不要停、什么时候停、怎么停,完全看自己。
throws InterruptedException
二、应用线程的场景
1.计算密集型任务
在计算密集型任务中,应用多线程,可以提高计算效率、提升整体速度。
2.执行流阻塞(最常见的场景)
当其中某个执行流阻塞时,为了能够还能继续处理其他业务,可以应用线程。
既然这个场景非常常见,那就举个例子吧💁♀️
以斐波那契数为例:
普通方法:
//这是普通的求斐波那契数的程序,有多组输入
//但有个缺点,如果用户输入的数字过大,程序就会产生类似于阻塞的现象,此时,也就无法计算下一个输入,这种情况就可以应用线程。
public class NoUseThread {
static long fib(int n){
if(n==0||n==1){
return 1;
}
return fib(n-1)+fib(n-2);
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNextInt()){
int n=scanner.nextInt();
long ret=fib(n);
System.out.printf("fib(%d)=%d",n,ret);
System.out.println();
}
}
}
应用线程:
public class useThread {
static long fib(int n){
if(n==0||n==1){
return 1;
}
return fib(n-1)+fib(n-2);
}
static class threadOfFib extends Thread{
int n;
threadOfFib(int n){
this.n=n;
}
@Override
public void run() {
long ret=fib(n);
System.out.printf("fib(%d)=%d",n,ret);
System.out.println();
}
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNextInt()){
int n=scanner.nextInt();
threadOfFib th=new threadOfFib(n);
th.start();
}
}
}
应用线程之后,当用户输入较大的数字,程序出现“阻塞”现象,但完全不影响程序继续处理用户之后输入的数字。
哈哈哈线程真好用🙆♀️
三、线程基本知识总结
1、什么是线程?
代表一个独立的执行流,属于某个进程,是CPU进行调度、分配CPU资源的基本单位。
2、OS为什么要引入线程?
分离进程的两个任务,即分配资源的基本单位(进程) ➕ 调度的基本单位(线程)。
3、什么场景会用到多线程?
- 计算密集型任务时,应用线程可以提高效率;
- 可能发生阻塞的场景时,应用多线程,不会影响别的工作的正常运行。
4、线程在Java中使用
- Thread对象和Runnable对象理解(注意用法);
- id、name、优先级、状态、前后台线程……;
- 启动线程、停止线程、等待停止……;
- 休眠、线程让步……
总结
线程的基础知识,就到这里啦,拜拜的🤗