0.前言
以往我们开发的程序大多是单线程的,即一个程序只有一个入口点,只有一条从头到尾的执行线路。然而现实世界中的很多过程都具有多线索同时进行的特性。例如,我们可以一边写着代码,一边收发邮件。事实上,这些操作都是又操作系统将资源分成若干个小块,然后再分配给每个程序使用,使这些程序看起来有并行的效果。
Java语言的一大特性就是对多线程的支持。多线程是指一个程序拥有多个程序的执行点,可以按照各自的执行线索共同工作的情况。虽然它们看起来是并行着工作的,不过这只是一种错觉。因为我们的计算机只能在一个时间片做一个线程的工作。
//
如果你的计算机是多核CPU,请无视前面这句话^_^
1.进程和线程
现代操作系统都支持多任务,主要的形式包括:(1)基于进程的多任务。(2)基于线程的多任务。
1.1线程的定义
进程:就是正在执行的程序,它有着自身的指定序列,拥有独立的数据空间,会占用一定的系统资源。more
线程
:是进程中的单一连续的指定流。线程依属于进程。一个进程可以有多个线程,同一个进程的线程s会共享该进程的资源。
//
举例:银联的客户可以在标注为银联的ATM机上存取钱
1.2线程的分类
Java中的线程分为用户线程User和守护线程Daemon.
//
通过setDaemon()方法指定其类型(true) ? Daemon : User
特点如下:
a.有自己独立的生命周期
b.一个用户线程User可以创造出用户线程和守护线程,而一个守护线程只能创造出守护线程。
c.用户线程可以转换成为守护线程,但只能在线程的新建态和终止态时转换。
// 关于线程的生命周期,耐心读下去。
d.守护线程是运行在系统的后台,通常做无限循环,进而服务于用户线程。其优先级低于用户线程
// 比如网游中的NPC。再比如Java中的GC(垃圾回收器)若程序中没有用户线程了,就不会有垃圾了,作为守护线程的GC就没有用武之
地了,这时JVM就会自动离开。
2.线程的状态及其生命周期
每个线程都有独立的生命周期,在它一个完整的生命周期中通常要经历下图这5-6种状态。
1.新建态
:
通过new关键字声明一个Thread类的对象 Thread t = new thread();会创建一个线程,这时系统并没有给处于新建态的线程t分配资源。
2.就绪态
:
通过调用t.start()方法会使线程t由新建态进入到就绪态(进入到就绪队列),这是t被分配到了系统资源。网上不少帖子在这时会说被调用了start()方法的线程,JVM会去调用该线程对象重写的run()方法。这说法没错,但不是立即执行,是要在就绪队列中排在第一位才能执行run()方法。附个小例子:
package thread;
public class ThreadTest {
public static void main(String[] args) {
ThreadInfo ti = new ThreadInfo();
ti.start();
System.out.println(ti.getThreadInfo());
System.out.println(ThreadInfo.getStaticInfo());
}
}
class ThreadInfo extends Thread {
private String strInfo = "define";
private static String STATIC_INFO = "define[S]";
public ThreadInfo() {
this.strInfo = "construcor";
STATIC_INFO = "construcor[S]";
}
public void run(){
try{
this.strInfo = "run";
STATIC_INFO = "run[S]";
}catch(Exception ex){
}
}
public String getThreadInfo(){
return this.strInfo;
}
public static String getStaticInfo(){
return STATIC_INFO;
}
}
执行上边的代码,控制台有时会打印:
construcor
construcor[S]
有时会打印:
construcor
run[S]
---------------------分割线-----------------------
3.运行态
:
排在就绪队列排头的线程会得到执行的机会。
运行态之后的线程对象会有以下3中结果:
1.代码执行完一个周期,如有需要改线程会再次进入就绪态,也就是所谓的就绪队列等待。关于就绪队列的算法,我 google了一下,根据OS的不同,其计算就绪队列的算法也不同,可以参见
3.线程的优先级
,有兴趣的可以Google。
2.代码执行结束后进去终止态。
3.代码继续执行,因需要某些权限进入阻塞态。
4.阻塞态/挂起态
:
若拥有了权限,程序会回到就绪队列。两者的区别是处于阻塞态的线程对象会占用系统资源,处于刮起态的对象则不会。
5.终止态
:
代码执行后,正常结束的状态。
我们通常所说的线程的生命周期就是除了终止态以外的其他4种状态。
---------------------分割线-----------------------
说了这些,估计没人会记住这些状态以及各状态之间的关系,那么咱换个说法:
下面咱
们
拿去
银
行
办
理
业务
来模
拟线
程的状
态转换
生命周期
:
1.
到银行
按号代表要办理
业务
,相当于
线程
的新建
态
。
2.
排在自己前面的人不多了,意味着自己
马
上可以
办业务
了,相当于排进了就绪队列,处于就绪态
。
3.
当前面没人了,叫道自己号儿的时候就可以办
理
业务了
,相当于运行
态
。
4.
没有再需要
办
理的
业务
就可以离开
银
行了,相当于
终
止
态
。如果
还
有第二个,第三个
业务
可以
继续办
,没有必要重新按号。
5.
前面
办业务
的人太墨迹了,一点
进
展也没有,就相当于阻塞
态
。
6.
等不了
了或
暂时银
行
办
理不了自己的
业务
,只能
叹
着气,离开
银
行,等能
办
理
时
再跑一趟。
---------------------分割线-----------------------
3.线程的优先级
在Java中,每个线程对象都有一个线程同步锁,一个线程等待队列当然也有一个优先级。
通过setPriority()方法设置优先级。1~10 数值越大级别越高,越先执行。详见API。
线程的调度
处于就绪状态的线程首先进入就绪队列排队等候CPU资源。同一时刻在排队的线程对象会有多个。我们可以通过设置线程的优先级来让任务较紧急的线程首先享用到CPU资源;而对于优先级相同的线程,JVM会随机抽取一个线程对象来执行。这种随机性很难通过代码看出来,不过大家姑且可以理解为某种先进先出的队列。至于其内部的"调度算法",我不是很了解,大家就靠自己吧。
4.线程的创建
在Java中创建一个线程的方法有两种:1.是通过Thread类的构造器创建 2.是通过实现Runnable接口
两者的不同之处在于:通过实现Runnable接口中的抽象run方法,定义出线程的行为,并不包含线程的生命周期。而通过Thread类的构造方法,不仅可以定义出线程的行为,还可以定义出完整的线程生命周期。
即:1.继承Thread类,覆盖run()方法,定义生命周期并实现本线程特有的行为。2.实现Runnable接口,实现该接口中的run()方法,定义线程特有的行为。
5.Thread类
参见Java API
6.线程组
参见Java API
7.线程同步
7.1线程同步的概念:
前面提到了”一个进程的多个线程可以共享该进程的资源“。而当多个线程访问同一批数据(共享资源)时,为了保证共享资源在同一时间段内只能允许被一个线程访问的技术叫线程同步。
7.2实现线程同步的方法
可以将修改共享资源的方法用synchronized关键字修饰。当线程调用synchronized方法时,对象将转为”锁定“状态。这里大家可以把用synchronized修饰的同步方法想象成一个里面有锁的公用电话亭。每次只能允许一个人使用电话,并且只允许电话亭内的人给电话亭上锁。这也解释了我前两天写的一个关于《线程同步的重进入》
的帖子中说明的问题。
synchronized关键字不仅可以修饰方法,还可以修饰一个代码块,例如:synchronized(对象) {代码体;}
这样写的好处是:1.减少了锁定时间。 2.降低锁定范围。3.降低系统的开销。
8.线程死锁的问题
在《线程同步的重进入》
里面也举了一个例子,大家可以看下。
9.volatile修饰符*
多线程中有主内存和工作内存之分,在JVM中,有一个主内存。专门负责所有线程的共享数据。而每个线程都有自己私有的工作内存,主内存和工作内存分别在JVM的stack栈和heap堆上。详见《Inside JVM》
以volatile
修饰的变量,表示将非原子数据定义为原子类型。
double和long变量是非原子型的,所以就会出现啊久前几天贴出的大项目中的bug的问题。详见《inside JVM》第八章线程的8.4节Double和Long变量的非原子处理。
// 总结一句 这个volatile关键字不安全,不到不得已还是不用为妙
---------------------------------------
以上就是有关线程的部分基础知识,欢迎讨论 不正之处请指正!
- 大小: 21.6 KB
- 大小: 27 KB
分享到:
相关推荐
本文将深入探讨“Java基础之线程游戏”,基于提供的源码和相关博客文章,我们将一起学习Java线程的基本概念、如何创建和管理线程,以及在实际开发中的应用。 线程是操作系统分配CPU时间的基本单元,它允许程序并发...
这套课程既可以作为从零基础开始...课程的主要内容涉及有JAVA基础课程、JAVA多线程与并发编程、数据库开发基础和进阶、Spring Framework、Spring进阶、Spring MVC框架、Spring boot、Java常用类库、Java异常处理等等
总结来说,Java基础多线程练习题主要涵盖了线程的创建、同步与通信、线程安全以及并发工具的使用。通过这些题目,你可以更好地理解线程的工作原理,学会在实际项目中有效利用多线程提高程序性能,避免潜在的问题。在...
个人关于java基础多线程的思维导图总结。0积分下载。如果认为有帮助,请关注点赞,日后还有更多免费资源。
Java程序中的线程是在操作系统级别的线程基础上进行抽象的。每个Java程序都有一个主线程,即由JVM启动并执行main方法的线程。线程代表了程序中的执行流,可以在不同的线程之间切换以共享CPU时间。线程的状态包括新建...
1. **多线程基础**:论文可能会首先介绍多线程的基本概念,解释为什么在JAVA中需要使用多线程,以及多线程如何提升程序的执行效率。这部分内容可能会涉及到线程的创建、启动、同步和通信等基础知识。 2. **JAVA多...
总之,掌握Java多线程的生命周期、创建、启动、同步以及线程池的使用是编写高效、稳定并发程序的基础。理解这些知识点对于解决并发编程中的问题,比如资源竞争、死锁、线程安全性等问题,至关重要。在实际开发中,...
通过分析并实践`threadTest`案例,我们可以深入理解Java多线程的原理和使用技巧,为编写高效并发程序打下坚实基础。同时,也要注意多线程编程中的死锁、活锁和饥饿等问题,合理设计线程间的交互,避免出现不可预期的...
1. **多线程基础**:多线程是Java编程中的一个重要概念,允许程序同时执行多个任务。在本示例中,通过创建多个`Thread`对象并调用它们的`run()`方法来实现并行处理数据库操作。 2. **数据库连接管理**:在多线程...
### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...
首先,我们需要了解Java中的线程基础。线程是程序执行的最小单位,一个进程可以包含多个线程。在Java中,我们可以使用`Thread`类或者`Runnable`接口来创建线程。然而,为了更好地管理和控制线程,Java并发包提供了如...
Java Socket基础 Socket在Java中由`java.net.Socket`和`java.net.ServerSocket`类表示。ServerSocket用于监听客户端的连接请求,而Socket则是客户端和服务端建立连接后的具体通信对象。一旦建立连接,双方可以通过...
Java多线程,Java基础,并发
这个实例提供了一个基础的进度条实现,但在实际应用中,可能需要考虑更多因素,如线程优先级、线程池的使用、异常处理、线程间的通信等。此外,如果是在图形用户界面环境下,还需要考虑UI更新的流畅性和用户体验。...
首先,`java.lang.Thread`类是Java中处理线程的基础,通过创建Thread对象并调用其`start()`方法可以启动一个新线程。然而,当多个线程需要共享资源或按照特定顺序执行时,就需要进行线程同步。 1. **synchronized**...
"Java基础"是学习Java编程的起点,涵盖了变量、数据类型、运算符、控制流程(如if语句、循环)、数组、类与对象、封装、继承、多态等核心概念。在"树形结构图"这一部分,我们将深入理解如何用Java来表示和操作树形...
本文将深入探讨Java中的基础概念,包括多线程、反射以及泛型,这些都是Java编程中至关重要的知识点。 首先,我们来讨论Java多线程。多线程允许程序同时执行多个独立的任务,极大地提高了应用程序的效率和响应性。在...
在Java编程语言中,多线程是程序设计中的一个重要概念,尤其在开发高效能和响应迅速的应用时。这个“JAVA-多线程 所有文件”压缩包很可能包含了一系列关于Java多线程学习的源代码示例和相关文档。下面我们将深入探讨...
1. **线程基础**:在Java中,线程是程序执行的基本单元,可以通过实现`Runnable`接口或继承`Thread`类来创建。`Runnable`接口更利于实现多线程,因为它允许实现类与其他接口一起使用,而`Thread`类则直接提供了线程...