深入理解Java核心知识点,多行代码带你学懂多线程,跳槽面试必备

185 阅读7分钟

今日分享开始啦,请大家多多指教~

一、线程的概念

(1)进程

进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。

进程的特征

  • 结构特征

  • 动态性

  • 并发性

  • 独立性

  • 异步性

进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。

多进程:在操作系统中能同时运行多个任务(程序);

(2)线程

线程(英语:thread)是操作系统能够进行运算调度的最小单位。

  • 它被包含在进程之中,是进程中的实际运作单位。

  • 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

线程:是进程的一个执行单元,是进程内可调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。

多线程:在同一个应用程序中有多个顺序流同时执行。

多线程的目的是为了最大限度地利用CPU资源。

二、线程的创建

Java中实现多线程的方法有两种:

继承java.lang包中的Thread类。

用户在定义自己的类中实现Runnable接口。

(1)Thread

1.Thread类

直接继承了Object类,并实现了Runnable接口。位于java.lang包中

封装了线程对象需要的属性和方法

继承Thread类——创建多线程的方法之一

  • 从Thread类派生一个子类,并创建子类的对象。子类应该重写Thread类的run方法,写入需要在新线程中执行的语句段。

  • 调用start方法来启动新线程,自动进入run方法。

2.Thread类的子类来创建线程

定义一个Thread的子类并重写其run方法:

image.png

生成该类的对象:

MyThread myThread = new MyThread();

启动或运行线程,Java虚拟机会自动启动线程,从而由Java虚拟机进一步统一调度线程,实现各个线程一起并发地运行。

myThread.start();

image.png

运行结果每一次都不同。因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。明确一点,在某一时刻,只能有一个程序在运行(多核除外)。

cpu在做着快速的切换,已达到看上去是同时运行的效果。我们可以形象把多线程的运行行为看作在相互抢夺cpu的执行权。

多线程的一个特性:随机性,谁抢到,谁执行,至于执行多长时间,由cpu决定。

3.在新线程中完成计算某个整数的阶乘

image.png

image.png

运行结果

image.png

结果说明

  • main线程已经执行完后,新线程才执行完。

  • main函数调用thread.start()方法启动新线程后并不等待其run方法返回就继续运行,thread.run函数在一边独自运行,不影响原来的main函数的运行。

4.构造函数

public Thread();

public Thread(Runnable target);

public Thread(String name);

public Thread(Runnable target, String name);

参数说明:

name:新线程对象的名字

5.常用方法

public void start();

启动该线程,将导致run方法被自动调用。该方法将立即返回,新线程将运行。

public void run();

必须覆盖该方法,在方法体中添加你想要在该线程中执行的代码。

public static void sleep(long millis) throws InterruptedException;

使当前正在执行的线程睡眠指定的时间。sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。 并不释放对象锁。也就是如果有Synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常。

public static void yield() ;

与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。

public final boolean isAlive();

用于测试某个线程是否还活着

public final void setPriority(int newPriority);

设置线程的优先级

public final int getPriority() ;

获得线程的优先级

public static Thread currentThread();

返回代表当前正在执行的线程的Thread对象

public final void wait(long timeout) throws InterruptedException;

当前线程被中断,并进入到一个对象的等待列表中,直到另外的线程调用同一个对象上的notify() 或notifyAll() 方法

public final void notify() ;

用于将对象等待列表中的任选的一个线程唤醒,使它再次成为可运行的线程

public final void notifyAll();

用于将对象等待列表中的所有线程唤醒,使它们再次成为可运行的线程。

image.png

image.png

image.png

(2)Runnable

1.Runnable接口

Thread类实现了Runnable接口

只有一个run()方法

更便于多个线程共享资源

Java不支持多继承,如果已经继承了某个基类,便需要实现Runnable接口来生成多线程

以实现runnable的对象为参数建立新的线程

start方法启动线程就会运行run()方法

2.Runnable接口的使用

使用Runnable接口实现计算某个整数的阶乘

image.png

3个Runnable类型的对象

image.png

image.png

image.png

三、线程间的数据共享

独立的同时运行的线程有时需要共享一些数据并且考虑到彼此的状态和动作

用同一个实现了Runnable接口的对象作为参数创建多个线程

多个线程共享同一对象中的相同的数据

image.png

运行结果

Starting threads

Thread1 going to sleep for 966

Thread2 going to sleep for 966

Threads started, main ends

Thread3 going to sleep for 966

Thread1 finished

Thread2 finished

Thread3 finished

说明:

因为是用一个Runnable类型对象创建的3个新线程,这三个线程就共享了这个对象的私有成员sleepTime,在本次运行中,三个线程都休眠了966毫秒。

四、多线程的同步控制

(1)同步方法

把synchronized当作函数修饰符

image.png

synchronized锁定的是调用这个同步方法对象。

当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。

但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。

静态同步synchronized方法与synchronized(class)代码块持有的锁一样,都是Class锁,Class锁对对象的所有实例起作用。

(2)同步代码段

synchronized线程同步关键字,实现互斥:

用于指定需要同步的代码段或方法,也就是监视区

可实现与一个锁旗标的交互。例如:

synchronized(对象){ 代码段 }

synchronized的功能是:首先判断对象的锁旗标是否在,如果在就获得锁旗标,然后就可以执行紧随其后的代码段;如果对象的锁旗标不在(已被其他线程拿走),就进入等待状态,直到获得锁旗标

当被synchronized限定的代码段执行完,就释放锁旗标

Java 使用监视器机制

每个对象只有一个“锁旗标” ,利用多线程对“锁旗标”的争夺实现线程间的互斥

当线程A获得了一个对象的锁旗标后,线程B必须等待线程A完成规定的操作、并释放出锁旗标后,才能获得该对象的锁旗标,并执行线程B中的操作

(3)模拟存票、售票过程

假定开始售票处并没有票,一个线程往里存票,另外一个线程则往出卖票

新建一个票类对象,让存票和售票线程都访问它。本例采用两个线程共享同一个数据对象来实现对同一份数据的操作

1.不进行同步控制

image.png

image.png

image.png

image.png

2.同步代码段

将需要互斥的语句段放入synchronized(object){}语句中,且两处的object是相同的。

image.png

image.png

3.同步方法

将互斥方法放在共享的资源类Tickets中

image.png

image.png

image.png

image.png

今日份分享已结束,请大家多多包涵和指点!