线程基础部分

一、线程和进程的概念

1.什么是进程?什么是线程?

进程是一个应用程序(1个进程是一个软件)。
线程是一个进程中的执行场景/执行单元。线程是cpu执行的最小单位

  • 一个进程可以启动多个线程。

2.进程和线程的关系?

进程可以看作是一个公司,而线程可以看作是里面的员工。
例如:阿里巴巴是一个公司,即是一个进程,里面的员工马云则是一个线程。

3.进程和进程之间的内存是否独立不共享?线程与线程之间呢?

  • 进程与进程之间的内存独立不共享。
    例如:打开王者荣耀是一个进程,打开酷狗音乐也是一个进程,二者不共享资源。

  • 线程A和线程B呢?
    在java语言中:
    线程A和线程B,堆内存和方法区内存共享。
    但是栈内存独立,一个线程一个栈。

例如:假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,互不干扰,各自执行各自的,这就是多线程并发。

4.多线程机制的目的?

每个进程有自己独立的地址空间,多并发请求,为每一个请求创建一个进程导致系统开销、用户请求效率低
java中之所以有多线程机制,目的就是为了提高程序的处理效率

5.什么时候数据在多线程并发的环境下会存在安全问题?

线程安全:如果一个操作序列,不考虑耗时和最远的消耗,在单线程下执行和多线程执行的情况下,最后得到的结果是相同的,这个操作序列就叫做线程安全操作。
三个条件:
1)多线程并发
2)有共享的数据
3)共享数据有修改的行为
满足上述三个条件,就会有线程安全的问题。

6.怎么解决线程安全问题?

当多线程并发,有共享数据,并且数据有被修改的行为,此时就存在线程安全问题,可以用线程同步机制(实际上就是线程不能并发,必须排队处理)

7.同步编程模型和异步编程模型

同步编程模型:线程t1和线程t2,在线程t1执行的时候,必须等待t2线程指向结束,或者说在线程t2执行的时候,必须等待t1线程指向结束,这就是同步线程模型。
效率较低,线程排队进行
异步编程模型:线程t1和线程t2,各自执行各的,t1不管t2,t2不管t1,谁都无需等待,这种编程模型叫做异步编程模型。
效率较高,多线程并发

二、线程的创建

1.编写一个类,直接继承java.lang.Thread,重写run方法

// 定义线程类
		public class MyThread extends Thread{
			public void run(){
			
			}
		}
		// 创建线程对象
		MyThread t = new MyThread();
		// 启动线程。
		t.start();

2.编写一个类,实现java.lang.Runnable接口,实现run方法

// 定义一个可运行的类
		public class MyRunnable implements Runnable {
			public void run(){
			
			}
		}
		// 创建线程对象
		Thread t = new Thread(new MyRunnable());
		// 启动线程
		t.start();

3.实现Callable接口,实现call方法


class MyCallable implements Callable {
	@Override
	public Object call() throws Exception {
		
	}

4.匿名内部类

        //创建线程对象,采用匿名内部类方法
        //通过一个没有名字的类,new一个对象
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
            }
        });
        t.start();

第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活。

三、线程的生命周期及常用方法解析

在这里插入图片描述

1.新建状态

刚new出来的新的线程对象

2.就绪状态

就绪状态的线程又叫做可运行状态,表示当前线程具有抢夺CPU时间片的权利(CPU时间片就是执行权)当一个线程抢夺到CPU时间片之后,就开始执行run方法,run方法的开始执行,标志着线程进入运行状态

3.运行状态

run方法的开始执行,标志着这个线程进入运行状态,当之前占有的CPU时间片用完之后会重新回到就绪状态,继续抢夺CPU时间片,当再次抢到CPU时间之后,会重新进入run方法,接着上一次的代码,继续往下执行

4.阻塞状态

当一个线程遇到阻塞事件,例如接收用户键盘输入或者sleep方法等,此时线程会进入阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片
阻塞分三种情况:
(1)等待阻塞(o.wait->等待队列):运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waiting queue)中;
(2)同步阻塞(lock->锁池):运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中;
(3)其他阻塞(sleep/join):运行的线程执行Thread.sleep(long ms)或thread.join方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时,join()等待线程终止或超时,或者I/O处理完毕时,线程重新转入可运行状态中。

5.死亡状态

run方法结束

6.常用方法

6.1.start():启动线程

启动一个新的线程,

6.2.run():子线程的执行体

run方法时子线程的执行体

6.3.sleep():线程休眠

线程调用后让当前线程进入休眠,进入“阻塞状态”,放弃占有cpu的时间片,让给其他线程使用,会抛出interruptExecption异常。
这行代码出现在线程A中,A线程进入休眠状态
这行代码出现在线程B中,B线程进入休眠状态

6.4.yield():线程让步

线程调用后会暂停当前线程的执行,让步于其他同优先级或更高优先级的线程执行。会使得当前线程由“运行状态”进入到“就绪状态”。

6.5.join():线程合并

线程调用后会暂停当前的线程,等待子线程的执行,join会处于并行状态的线程合并为串行状态。
例如:加入线程A中调用B.join(),则线程A会被暂停执行,并让线程B先执行,知道线程B执行结束,A才会执行。

6.6.interrupt():线程中断

interrupt方法可以中断当前的线程,线程进入到”阻塞状态“或者时线程运行结束。

    public void interrupt() {
        if (this != Thread.currentThread()) {
            checkAccess();

            // thread may be blocked in an I/O operation
            synchronized (blockerLock) {
                Interruptible b = blocker;
                if (b != null) {
                    interrupt0();  // set interrupt status
                    b.interrupt(this);
                    return;
                }
            }
        }

该方法的特点

  • 如果线程当前状态是可中断的状态(sleep\join\wait等方法导致线程进入到阻塞状态),在任意的其他线程中调用(线程名).interrupt方法时,那么线程会立即抛出interruptException异常,退出阻塞状态。
  • 如果线程当前处于运行状态,吊桶(线程名).interrupt方法,线程会继续执行,知道线程发送sleep\join\wait等方法的调用会进入到阻塞状态,随后会抛出interruptException异常,退出阻塞状态。

6.7.deamon:守护线程

守护线程作用时服务于非守护线程,垃圾回收线程就是一个典型的守护线程。
守护线程的生命周期时依赖于非守护线程的。

6.8.priority:线程优先级

java中的线程分为10个优先级,一般默认优先级为5.
线程优先级并不绝对按着设定的顺序执行,最终决定权在操作系统。

四、相关混淆概念

1.并行与并发:

并发:
指多个线程操作同一个资源(CPU),不是同时执行,而是交替执行。
并发的特性
原子性:如果一个操作序列是不可被分割的,那就是一个原子操作,也叫做操作具有原子性。

a++;//a++可以被分割为a=a+1;故该操作不具有原子性。

在并发编程中通过同步技术(lock)或者是Concurrent数据集合来保证操作安全性。
可见性:一个变量在多个线程中是共享的,如果一个线程修改了这个变量的值,那么在其他线程中可以立即知道该变量的值被改变,则称这个修改是具有可见性的。
【类似这种临时变量会有主内存和工作内存(各个线程中独有的内存)都会保存一份】
有序性;在一个线程内存观察,所有的操作都是有序的。在线程之间观察,从一个线程来观察其他线程,所有线程都可以交叉并行执行,是正序的。
并行:时真正意义上的同时执行,多核CPU,每一个线程使用一个单独的CPU的资源来运行。

2.临界资源和临界区

临界资源:一般指的是内存资源,CPU资源,一个时刻只允许一个线程访问,一个线程访问临界资源时,其他线程时不能使用的。临界资源是非可剥夺性资源。
临界区:在一个线程中可以访问临界资源的程序代码的片段。(注意:不是CPU,不是内存资源,是代码片段)
使用临界区的使用原则:“空闲让进、忙则等待、有限等待、让权等待”

  • 空闲让进:当无进程处于临界区时,允许进程进入临界区,并且只能在临界区运行有限的时间。
  • 忙则等待:当有一个进程在临界区是,其他需要进入临界区的进程必须等待,以保证进程互斥地访问临界资源。
  • 有限等待:对要求访问临界资源的进程,应保证进程等待有限时间后进入临界区,以免陷入“饥饿”状态。
  • 让权等待:当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入“忙等”状态。 假如所需要的临界资源不是CPU资源时可以放弃对CPU的使用,从而争夺所需要的临界资源。

五、线程简单问题及其回答

1.使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束?

是,main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在压栈弹栈

2.什么是真正的多线程并发?

t1线程执行t1的。
t2线程执行t2的。
t1不会影响t2,t2也不会影响t1。这叫做真正的多线程并发。

3.对于单核的CPU来说,真的可以做到真正的多线程并发吗?

对于多核的CPU电脑来说,真正的多线程并发是没问题的。
即:4核CPU表示同一个时间点上,可以真正的有4个进程并发执行。
单核的CPU表示只有一个大脑:
不能够做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉。
对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于CPU的处理速度极快,多个线程之间频繁切换执行,给人来的感觉是:多个事情同时在做!!!!!
即:两个线程频繁切换,给人的感觉是同时进行的。

4.多线程和多进程有哪些区别?

1)每个进程拥有自己独有的数据,线程共享数据,线程之间的通信相比于进程之间的通信更有效更容易
2)线程相比于进程创建/销毁开销更小
3)进程是资源分配的最小单位,线程是cpu调度的最小单位
4)多进程程序更加健壮,多线程程序只要有一个线程挂掉,对其共享资源的其他线程也会产生影响
5)如果追求速度,选择线程
如果频繁创建和销毁,选择线程
如果追求系统更加稳定,选择进程

5.start()方法和run()方法的关系

start方法:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后瞬间就结束了
(这段代码只是为了开启一个新的栈空间,只要新的栈空间开辟出来,start()方法就结束了,线程就启动成功了)
启动成功的线程自动调用run方法,并且run方法在分支栈的栈底部(压栈)
run方法在分支栈的底部,main方法在主栈的底部,run和main是平级的

mythread.start();

这行代码不结束,下面不会进行,只是该行代码瞬间结束,这里的代码还是在主栈中进行。

mythread.run();

不会启动线程,不会分配新的分支栈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值