多线程线程
Posted 烟锁迷城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程线程相关的知识,希望对你有一定的参考价值。
目录
1、线程的概念
开始学习多线程之前,要弄清出一个概念,什么是线程?
线程是轻量级的进程,每一个进程内都包含N个线程。
那么问题又来了,什么是进程?
进程是每一个系统操作的执行操作。
实际上,在进行系统操作时,无论是什么操作,都是需要CPU资源和磁盘IO的,磁盘IO相比其他操作,速度很慢,而CPU资源不可能等待IO,它非常宝贵,所以只能让CPU去执行其他的操作,这就是CPU的时间片切换
为了能让CPU有切换的进程,系统设计了一种多进程,多个进程同步进行,互相隔离互不影响,但进程太重了,为了轻量化,就产生了线程的概念
2、线程的特点
线程有两个特点,异步和并行
- 异步:无需等待,分别执行程序
- 并行:依赖CPU核心数
3、线程的使用
3.1、thread类
线程可以通过继承thread类,重写run方法,用start方法来进行调用。
public class ThreadDemo extends Thread
@Override
public void run()
try
Thread.sleep(2000);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("thread show");
public static void main(String[] args)
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
System.out.println("main show");
3.2、runnable接口
实现Runnable接口后,重写run方法,用thread类的start方法进行调用
public class RunnableDemo implements Runnable
@Override
public void run()
try
Thread.sleep(2000);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("thread show");
public static void main(String[] args)
RunnableDemo runnableDemo = new RunnableDemo();
new Thread(runnableDemo).start();
System.out.println("main show");
3.3、Callable<T>接口
实现Callable<T>接口,重写call方法,可以实现有返回值的线程,但是要注意,这里future的get方法是阻塞的,因为需要返回值。
public class CallableDemo implements Callable<String>
@Override
public String call() throws Exception
Thread.sleep(2000);
return "callable show";
public static void main(String[] args) throws ExecutionException, InterruptedException
ExecutorService executorService = Executors.newFixedThreadPool(1);
CallableDemo callableDemo = new CallableDemo();
Future<String> future = executorService.submit(callableDemo);
System.out.println(future.get());
System.out.println("main show");
4、线程的启动过程
无论是继承Thread还是实现Runable接口,其重写的都是run方法,但执行的是start方法,因为run方法只是回调函数,真正启动线程的是start。
Thread的start方法是在JVM层面起作用,但是java和JVM都没有线程,真正要调度的是操作系统的线程
JVM的跨平台特性可以让任何操作系统在start方法执行之后创建线程,开始线程,此时系统会根据CPU调度算法将线程分配给CPU
当CPU执行到某个线程Thread时,会调用其run方法,完成回调。
5、线程的生命周期
java线程有六种状态,分别是new(创建),runnable(运行),time_waiting(超时等待),waiting(等待),blocked(阻塞),terminated(死亡)。
系统线程的五种状态,分别是新生,就绪(ready),运行(running),等待(waiting),死亡。
- 一个线程先被创建,然后进入运行(分为就绪,运行两种)状态
- 加锁(synchronized修饰)会进入阻塞状态
- 使用不带等待时间的等待函数sleep(0),wait(),join(),LockSupport.park()会进入等待状态
- 使用加入唤醒时间的等待函数sleep(time),wait(time),join(time),LockSupport.parkUntil(time)会进入超时等待状态
- notify(),notifyall(),LockSupport.unpark()可以唤醒沉睡中的线程,使之进入运行(分为就绪,运行两种)状态
- run函数运行结束后,线程进入死亡状态。
6、线程的停止
6.1、中断标志
线程的停止可以使用stop方法,但是这是一个简单粗暴的命令,可能会导致强制停止,因此这里使用中断标志来停止。
相比于强制停止的stop方法,中断标志是一种更温和的终止线程的方式,它将当前线程是否终止的决定权交给线程。
中断标志看起来可能不够熟悉,不过InterruptedException异常想必很多人都遇到过,在执行sleep,wait等带有等待或超时等待的方法时,编译器会强制要求抛出此错误,而这个错误,就是中断标志错误。
- 将一个共享变量,即中断标志从false设置为true
- 将进入等待或超时等待状态下的线程唤醒,执行下一步的操作。
6.2、中断方法与复位
在中断标志中,有三个方法是很关键的,它们是interrupt(),isInterrupted()和interrupted()。
这三个方法是非常类似的,接下来我们来依次分析。
6.2.1、获取中断标志:isInterrupted()
isInterrupted()方法的使用方式为Thread.currentThread().isInterrupted(),获取当前线程的中断标志,默认是false,下面是示例代码
public class Demo implements Runnable
@Override
public void run()
boolean interrupted = Thread.currentThread().isInterrupted();
System.out.println(interrupted);
System.out.println("processor stop");
public static void main(String[] args) throws InterruptedException
Thread thread = new Thread(new Demo());
System.out.println("main show");
thread.start();
可以看到,在默认状态下,中断标志是false
6.2.2、线程中断:interrupt()
interrupt()方法的使用方式为Thread.currentThread().interrupt(),将调用此方法的线程的中断标志置为true
可以看到下面的例子中,执行interrupt()方法之后循环会被中断,处于等待之中的线程会被唤醒然后进入到catch代码块中,继续执行中断方法interrupt(),会将线程停止。
public class Demo implements Runnable
@Override
public void run()
while (!Thread.currentThread().isInterrupted())
try
System.out.println("thread show");
Thread.sleep(2000);
catch (InterruptedException e)
e.printStackTrace();
Thread.currentThread().interrupt();
System.out.println("processor stop");
public static void main(String[] args) throws InterruptedException
Thread thread = new Thread(new Demo());
System.out.println("main show");
thread.start();
thread.interrupt();
如果把catch代码块中的interrupt()去掉,那么线程将继续执行完,不会中断,这就是所谓的中断复位
6.2.3、中断复位:interrupted()
interrupted()方法的使用方式为Thread.interrupted(),将调用此方法的线程的中断标志置为false,是主动的复位
可以看到,interrupted()不同于上两个方法,这只是Thread的静态方法,查看源码可知,此方法检测当前线程是否被中断, 如果是返回true , 否则返回false,如果是中断状态,则复位当前线程
public static boolean interrupted()
return currentThread().isInterrupted(true);
interrupted()方法是主动复位,还有被动复位的,那就是强制抛出错误InterruptedException,这就解释了之前为什么如果不再catch代码块中进行操作的话,线程会继续执行下去,因为InterruptedException自动将中断标志复位了。
中断标志复位的友好性在于,虽然中断的发起可以在线程之外,但具体的内部处理却可以完全由线程来进行控制。
以上是关于多线程线程的主要内容,如果未能解决你的问题,请参考以下文章