Java基础之多线程简述
首先,要辨析进程与线程的概念:
进程是程序执行的过程,它持有资源和线程,相对于程序本身而言具有动态性。
线程是系统中最小的执行单元,同一个进程中可能有多个线程,它们共享该进程持有的资源。线程的通信也称为线程的交互,方式主要有互斥和同步。同步是指线程之间通过共同协作完成某项工作,线程间具有次序性;互斥是指线程间对某一资源的竞争,一次只能有一个线程访问该资源。
介绍完了这些基本概念,下面简单介绍一下Java对多线程的支持.
java中通过类Thread和接口Runnable来实现多线程的操作。它们都有一个run方法来指定线程工作时执行的代码。
Thread类的常用方法
|
类别 |
名称 |
简介 |
|
线程的创建 |
Thread() |
|
|
Thread(String name) |
||
|
Thread(Runnable target) |
||
|
Thread(Runnable target, String name) |
||
|
线程的方法 |
void start() |
启动线程 |
|
static void sleep(long millis) |
线程休眠 |
|
|
static void sleep(long millis, int nanos) |
||
|
void join() |
某线程调用join方法后,使其他线程等待该线程终止 |
|
|
void join(long millis) |
||
|
void join(long millis, int nanos) |
||
|
static void yield() |
当前正在运行的线程立刻释放处理器,重新加入竞争处理器的队列 |
|
|
获取线程引用 |
static Thread currentThread() |
返回当前正在运行的线程的引用 |
使用多线程有两种方式,一种是直接继承Thread类,一种是实现Runnable接口
- 继承Thread类,在run方法中指定需要线程执行的代码,通过getName()和setName()方法去访问线程名称。通过该类对象的start方法来开启线程。
- 实现Runnable接口,重写run方法来指定需要线程执行的代码,然后把该类的对象作为参数传递给Thread对象来执行。
另外,通过volatile关键字声明的成员变量可以保证当其他线程修改该成员变量后,本线程可以正确读取到此成员变量的值。
线程的状态
请结合OS中进程的5态来思考。以下线程状态和方法的介绍来自DreamSea(张小哲)
- 新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);
- 就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);
- 运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);
- 阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)
- 死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thread已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。

Ø线程的方法(Method)、属性(Property)
1)优先级(priority)
每个类都有自己的优先级,一般property用1-10的整数表示,默认优先级是5,优先级最高是10;优先级高的线程并不一定比优先级低的线程执行的机会高,只是执行的机率高;默认一个线程的优先级和创建他的线程优先级相同;
2)Thread.sleep()/sleep(long millis)
当前线程睡眠/millis的时间(millis指定睡眠时间是其最小的不执行时间,因为sleep(millis)休眠到达后,无法保证会被JVM立即调度);sleep()是一个静态方法(static method) ,所以他不会停止其他的线程也处于休眠状态;线程sleep()时不会失去拥有的对象锁。 作用:保持对象锁,让出CPU,调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留一定的时间给其他线程执行的机会;
3)Thread.yield()
让出CPU的使用权,给其他线程执行机会、让同等优先权的线程运行(但并不保证当前线程会被JVM再次调度、使该线程重新进入Running状态),如果没有同等优先权的线程,那么yield()方法将不会起作用。
4)thread.join()
使用该方法的线程会在此之间执行完毕后再往下继续执行。
5)object.wait() 当一个线程执行到wait()方法时,他就进入到一个和该对象相关的等待池(Waiting Pool)中,同时失去了对象的机锁—暂时的,wait后还要返还对象锁。当前线程必须拥有当前对象的锁,如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常,所以wait()必须在synchronized block中调用。sleep()和wait()方法的最大区别是:sleep()睡眠时,保持对象锁,仍然占有该锁;而wait()睡眠时,释放对象锁。但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。
6)object.notify()/notifyAll()
唤醒在当前对象等待池中等待的第一个线程/所有线程。notify()/notifyAll()也必须拥有相同对象锁,否则也会抛出IllegalMonitorStateException异常。
7)Synchronizing Block
Synchronized Block/方法控制对类成员变量的访问;Java中的每一个对象都有唯一的一个内置的锁,每个Synchronized Block/方法只有持有调用该方法被锁定对象的锁才可以访问,否则所属线程阻塞;机锁具有独占性、一旦被一个Thread持有,其他的Thread就不能再拥有(不能访问其他同步方法),方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。
正确停止Java线程
非正确停止的方法:stop()
要正确停止线程,应该使用正确的退出标记。正常情况下run方法执行完毕线程就停止了,但是有些情况下run方法中需要while循环保持轮询,所以应该为while循环设置合适的退出条件,即退出标记,保证线程正确停止。
或者使用interrupt()方法的初衷并不是要停止线程,正常情况下,调用该方法可以将中断标记设置为TRUE。但是,当某个线程因为调用了wait()或者sleep()等方法而被阻塞时,此时调用interrupt()方法并不能正确的将interrupted标记设置为TRUE,并且同时会抛出中断异常。
争用条件:当多个线程同时共享访问同一个内存数据时,每个线程都尝试操作该数据,从而导致数据被破坏。
线程的互斥与同步
互斥是指在同一时刻只有一个线程可以对临界区进行操作。在JAVA中,可以通过synchronized块或者方法来实现。
在synchronized块中,需要对某个对象进行加锁,并将需要互斥的代码放入synchronized块中,从而来实现互斥行为。获得该锁的进程可以进入该synchronized块中.
而同步则是线程之间的一种通信机制,通过同步可以规定线程执行的顺序。例如,当线程不满足访问某资源时,可以通过调用锁对象的lock.wait()方法,使该线程让出CPU,让出锁,并在该锁对象的waitset中等待。满足条件时,可以通过lock.notify()方法随机唤醒一条线程,lock.notifyAll()则唤醒该waitset中所有的线程,使它们重新竞争该锁。被唤醒的线程从wait()方法处继续执行。
Java基础之多线程简述的更多相关文章
- Java基础技术多线程与并发面试【笔记】
Java基础技术多线程与并发 什么是线程死锁? 死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,我们就可以称 ...
- 关于java基础、多线程、JavaWeb基础、数据库、SSM、Springboot技术汇总
作者 : Stanley 罗昊 本人自行总结,纯手打,有疑问请在评论区留言 [转载请注明出处和署名,谢谢!] 一.java基础 1.多态有哪些体现形式? 重写.重载 2. Overriding的是什么 ...
- Java基础之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- Java基础之多线程框架
一.进程与线程的区别 1.定义: 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比 ...
- Java基础之多线程详细分析
在了解多线程之前,先来了解一下进程与线程之间的关系. 进程和线程: 进程是指在系统中正在执行的一个程序,每个进程之间是独立的. 线程是进程的一个基本执行单元.一个进程要想执行任务,必须得有线程(每1个 ...
- java基础知识 多线程
package org.base.practise9; import org.junit.Test; import java.awt.event.WindowAdapter; import java. ...
- Java基础之多线程
1.进程和线程: 进程:正在进行的程序.每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元. 线程:进程内部的一条执行路径或者一个控制单元. 两者的区别: 一个进程至少有一个线程 ...
- 黑马程序员——【Java基础】——多线程
---------- android培训.java培训.期待与您交流! ---------- 一.概述 (一)进程 正在执行中的程序,每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控 ...
- 黑马程序员——JAVA基础之多线程的线程间通讯等
------- android培训.java培训.期待与您交流! ---------- 线程间通讯: 其实就是多个线程在操作同一个资源,但是动作不同. wait(); 在其他线程调用此对象的notif ...
随机推荐
- jq 获取表单所有数据
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- js判断数组中是否包含某个值
/** * 判断数组中是否包含某个值 * @param arr 数组 * @param str 值 * @returns {boolean} */ function contains(arr, str ...
- sessionStorage和localStorage存储的转换不了json
先说说localStorage与sessionStorage的差别 sessionStorage是存储浏览器的暂时性的数据,当关闭浏览器下次再打开的时候就不能拿到之前存储的缓存了 localStora ...
- react获取url查询参数
继承自React.Component的this.props.location.query对象下有当前url的各种查询参数.简单的例子:在控制台打印这个对象 import React from 'rea ...
- webpack学习(五)—webpack+react+es6(第1篇)
如果你看过webpack学习系列的前一个文章,接下来做的东西会比较简单 :webpack学习(四)— webpack-dev-server react发展的很快,现在大部分开发react相关的项目,都 ...
- GFS分布式文件系统理论个人总结
GlusterFS 两种模式 可以通过TCP/IP和RDMA高速网络互连,客户端可通过原生Gluster协议访问数据 没有GlusterFS客户端的可以通过NFS/CIFS标准协议通过存储网关访问数据 ...
- PAT_A1147#Heaps
Source: PAT A1147 Heaps (30 分) Description: In computer science, a heap is a specialized tree-based ...
- eas之利用KDTableHelper批量填充数据
// 下述代码将创建一个KDTable,并指定列名.表头单元格的显示值.和表体数据KDTable table = new KDTable();String [] columnKeys = new St ...
- 对 p 开 n 次方 (数学推论)
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> us ...
- 洛谷P1012 拼数【字符串+排序】
设有nn个正整数(n≤20)(n≤20),将它们联接成一排,组成一个最大的多位整数. 例如:n=3n=3时,33个整数1313,312312,343343联接成的最大整数为:3433121334331 ...