携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
前言
项目中我们经常会用到使用到多线程,多线程也是比较难的难点,关于并发编程的相关知识如下:
本文将详细讲解JUC的基础之线程。
进程与线程之间关系
一个操作系统中可以有多个进程,一个进程中可以包含一个线程(单线程程序),也可以包含多个线程(多线程程序)。
进程
进程是一个在内存中运行的应程序,每个进程都有自己独立的一块内存空间,一个进程可以有多个线程。比如window的一个运行的程序就是一个进程。
线程
- 线程是轻量级的进程,是程序执行的最小单元,使用多线程而不是多进程去进行并发程序的设计,是因为线程间的切换和调度的成本远远小于进程。
- 在同⼀个进程内可以执⾏多个任务,⽽这每⼀个任务我们就可以看做是⼀个线程 ⼀个进程会有1个或多个线程的。多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈。
进程与线程区别
-
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
-
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
-
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
-
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
-
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行
创建线程的几种方式
创建线程有三种方式,分别是Thread、Runnable、Callable.
thread创建线程
Thread thread = new Thread(()->{
System.out.println("this is thread");
});
thread.start();
通过Thread创建线程,start()方法启动线程。
实现Runnable
MyRunnable runnable =new MyRunnable();
Thread runableThread =new Thread(runnable);
runableThread.start();
通过实现Runnbale接口来创建线程.
实现Callable
public class CallableTest<String> implements Callable<String>
{
private String str;
CallableTest(String s){
this.str = s;
}
@Override
public String call() throws Exception
{
return this.str;
}
}
//
Callable<String> callable =
new CallableTest<String>("this my callable");
FutureTask<String> task = new FutureTask<String>(callable);
Thread futureThread =new Thread(task);
futureThread.start();
System.out.println(task.get());
说明:因为Thread只能接收Runnable接口,而Callable并为实现Runnable接口,需要通过FutureTask类作为简单适配类。
线程状态
java线程的状态分为:New(新建)、RUNNABLE(可运行)、RUNNING(运行中)、BLOCKED(阻塞)、Dead(死亡)
线程状态的转换如下图:
线程常用方法
线程常用方法包含了join、yield、sleep等方法。
Join
线程A在运行时,线程Bjoin(),之后,线程A会等待直到线程B运行完之后,才开始执行。
相关示例:
public class JoinAThread extends Thread
{
@Override
public void run() {
try {
JoinBThread b = new JoinBThread();
b.start();
b.join();//B线程join之后,A线程需要等待B运行完之后才执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A执行任务。。。。。。。");
}
}
public class JoinAThread extends Thread
{
@Override
public void run() {
try {
JoinBThread b = new JoinBThread();
b.start();
b.join();//B线程join之后,A线程需要等待B运行完之后才执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A执行任务。。。。。。。");
}
}
public class ThreadJoinTest
{
public static void main(String[] args)
{
JoinAThread a =new JoinAThread();
a.start();
}
}
执行结果:
Yield
Yield的作用是让正在执行的线程让出CPU的执行权限,使得CPU可以去执行其他任务。
相关示例:
public class ThreadA implements Runnable
{
@Override
public void run()
{
Thread.yield();
System.out.println("this thread name:"+Thread.currentThread().getName());
}
}
public class ThreadB implements Runnable
{
@Override
public void run()
{
System.out.println("this thread name:"+Thread.currentThread().getName());
}
}
public class ThreadYield
{
public static void main(String[] args)
{
ThreadA a =new ThreadA();
Thread threadA =new Thread(a);
threadA.setName("tA");
ThreadB b =new ThreadB();
Thread threadB =new Thread(b);
threadB.setName("tB");
threadA.start();
threadB.start();
}
}
执行结果:
Sleep
主要是让当前线程“睡眠”指定时间的。
总结
本文对于JUC的线程进行详细的讲解,如有疑问请随时反馈。