java线程基础知识----线程基础知识
不知道从什么时候开始,学习知识变成了一个短期记忆的过程,总是容易忘记自己当初学懂的知识(fuck!),不知道是自己没有经常使用还是当初理解的不够深入.今天准备再对java的线程进行一下系统的学习,希望能够更好的理解使用java线程.
1. 什么是线程,线程与进程的差别?(这一块内容我想我已经有了一个理解,这里就不再做记录了)
2.java线程的状态:
从百度上随便找了一张图,图中已经很清楚的标注了thread的各个状态以及状态的变化的场景.我们会在接下来的章节中进行相关讲解.
3.java实现多线程的方式:
A: 继承Thread类:(在下面的章节进行源码分析)
public class ThreadTest {
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
thread1.start();
}
}
class Thread1 extends Thread{
public void run () {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
B: 实现Runnable接口.
public class ThreadTest {
public static void main(String[] args) {
Thread thread2 = new Thread(new Thread2());
thread2.start();
}
}
class Thread2 implements Runnable{
@Override
public void run() {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4. 实现多线程的两种方法的差别:
A. 众所周知java不允许多继承,那么我们集成Runnable接口实现多集成就能够很好的避免这个限制.
B.集成Runnable接口实现多线程有利于程序操作共享资源(后面会提到)
这个理解起来很简单: 我们继承了Thread类实现run方法之后我们可以发现这样一个问题,我们再进行线程实例化之后我们必须分别启动线程任务.
而我们实现Runnable接口的话,我们可以实例化多个Thread类来运行这个任务.
当然集成Thread类也并不是不能完成共享资源的分发,而是比较费劲.
5. 实例化:我们在初始化Thread类的时候会调用Thread内部的init方法,即便是我们不提供任何参数.init函数的结构: private void init(ThreadGroup g, Runnable target, String name,long stackSize)
参数有:ThreadGroup,Target,name.stackSize,其中ThreadGroup会递归去调用父类的getThreadGroup来进行初始化,等待初始化完成之后我们会通过ThreadGroup调用checkAccess()方法来检查当前线程是否有权限操作此线程.
java源码:
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */ /* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
} /* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
} /* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
其中Thread类的daemon,priority属性会由父类继承.
6.Thread类中的方法:
Thread.sleep(): 此方法调用的是native的方法,本人不才,记得当初看过jdk源码,但是并没看懂底层实现。sleep方法是使当前线程休眠,讲cpu占用权交给其他任意优先级的线程。但是我们应该注意:sleep方法并不会释放对象锁。
Thread.join(): 记得当初查看api的时候觉得api对join方法的解释非常模糊。到底是谁等待谁结束,这有歧义。其实是这样的,在java7 api中介绍的很清楚,是调用join的线程等待被调用线程执行结束之后再开始执行。这里有一个很值得注意的问题,join的底层调用的是wait方法,而且是循环调用,源码如下:
long base = System.currentTimeMillis();
long now = 0; if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
} if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
我们可以看到源码中join方法会在while循环中一直调用wait方法,这是因为如果wait的时间是1000ms,如果在100ms的时候另外一个线程调用了notifyAll方法,那么线程就会苏醒。还要注意第二个问题,就是join调用wait方法,那么我们知道当main线程调用ThreadA.join的时候,main函数会获取ThreadA对象的锁。当ThreadA线程执行完成之后释放该对象锁。下面我们通过一个例子来验证一下上面的论述:我们新建三个线程,B,C,D,然后在B-C-D中进行循环调用。
public class ThreadTest {
public static ThreadB threadB = new ThreadB();
public static void main(String[] args) throws InterruptedException{
System.out.println("main线程开始调用B.join");
threadB.start();
threadB.join();
}
}
class ThreadB extends Thread{
public void run(){
try {
System.out.println("ThreadB执行ThreadC.join");
ThreadC threadC = new ThreadC();
threadC.start();
threadC.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadC extends Thread{
public void run(){
try {
System.out.println("ThreadC执行ThreadD.join");
ThreadD threadD = new ThreadD();
threadD.start();
threadD.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadD extends Thread{
public void run(){
try {
System.out.println("ThreadD执行ThreadB.join");
ThreadTest.threadB.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果:
main线程开始调用B.join
ThreadB执行ThreadC.join
ThreadC执行ThreadD.join
ThreadD执行ThreadB.join
可以发现我们的程序一直停留在这个位置,这是因为三个线程满足了死锁的条件,同时也可以证明,thread.join()的调用者必定会获取被调用者的锁。
Thread.yield: 此方法与sleep方法类似,但是需要注意一个问题就是Thread.yield只能讲cpu的使用权转交给同等优先级的线程。
Thread.start: 最后我们谈一谈Thread.start方法,想必大家都知道Thread.start方法会启动线程,并且执行run方法中的内容。你是否会想我们为什么不直接调用Thread.run来执行呢?其实是这样的,如果我们调用Thread.run来执行的话,jvm并不会真正的启动一个线程,而是将其当做一个普通的方法执行。而调用start的话,在start内部会调用start0方法来新建一个线程。
至此: 线程的基础知识就结束了,下一章我们会学习关于线程锁的相关知识。
java线程基础知识----线程基础知识的更多相关文章
- Java并发之线程管理(线程基础知识)
因为书中涵盖的知识点比较全,所以就以书中的目录来学习和记录.当然,学习书中知识的时候自己的思考和实践是最重要的.说到线程,脑子里大概知道是个什么东西,但很多东西都还是懵懵懂懂,这是最可怕的.所以想着细 ...
- java核心-多线程(4)-线程类基础知识
1.并发 <1>使用并发的一个重要原因是提高执行效率.由于I/O等情况阻塞,单个任务并不能充分利用CPU时间.所以在单处理器的机器上也应该使用并发. <2>为了实现并发,操作系 ...
- [C#.NET 拾遗补漏]11:最基础的线程知识
线程的知识太多,知识点有深有浅,往深的研究会涉及操作系统.CUP.内存,往浅了说就是一些语法.没有一定的知识积累,很难把线程的知识写得全面,当然我也没有这个能力.所以想到一个点写一个点,尽量总结一些有 ...
- JAVA面试题集之基础知识
JAVA面试题集之基础知识 基础知识: 1.C 或Java中的异常处理机制的简单原理和应用. 当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就 ...
- Java 面试知识点解析(一)——基础知识篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- Java基础篇——线程、并发编程知识点全面介绍(面试、学习的必备索引)
原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10739579.html,希望大家多多支持!!! 一.线程基础 1.线程与进程 线程是指进程 ...
- java多线程系类:基础篇:09之interrupt()和线程终止方式
概要 本章,会对线程的interrupt()中断和终止方式进行介绍.涉及到的内容包括:1. interrupt()说明2. 终止线程的方式2.1 终止处于"阻塞状态"的线程2.2 ...
- JAVA基础拾遗-论线程池的线程粒度划分与深浅放置
摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...
- Java中实现异常处理的基础知识
Java中实现异常处理的基础知识 异常 (Exception):发生于程序执行期间,表明出现了一个非法的运行状况.许多JDK中的方法在检测到非法情况时,都会抛出一个异常对象. 例如:数组越界和被0除. ...
- Java视频扩展知识 线程池的了解
Java视频扩展知识 线程池的了解 1.简单介绍: Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的 ...
随机推荐
- C# Stopwatch与TimeSpan详解
http://www.cnblogs.com/newstart/archive/2012/09/21/2696884.html
- Mysql的链接超时异常CommunicationsException
原文是在博客上的:小重合之旅 链接如下:未经过作者同意,这里注明下. http://blog.csdn.net/bluesnail216/article/details/15810119 1,问题现象 ...
- CDH- 集群时间同步ntp问题解决
在CDH集群中发现有两台机器获取不到心跳(),导致监控不了机器状态,出现告警 可以使用ntpstat检查与ntp 服务器的时间偏差状态 使用 ntpstat 发现没有同步到ntp时间服务器,运行 nt ...
- BZOJ 3357 [Usaco2004]等差数列:map优化dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3357 题意: 给你n个数a[i],让你找出一个最长的是等差数列的子序列. 题解: 表示状态 ...
- 【前端】【javascript】es6中的遍历器接口Iterator
好久没发文章啦-.-为了证明我还活着,我决定从笔记里面抓一篇还算不乱比较像文章的发出来... 这些笔记是我在学es6的时候断断续续记录的,最近会一份一份整理陆陆续续发出来,顺便也自己再看一遍.我学习e ...
- ADO:游标与RecordSetPtr
一.游标的属性设置: 游标是记录集recordset中用于游动逐个查找一条记录的一种机制.查询的数据返回后,通过游标来逐条获取查询的记录. 因此在配置数据库查询方式前可配置游标的属性: rs.Curs ...
- 欧拉函数(汇总&例题)
定义 欧拉函数 $\varphi(n)$表示小于等于$n$的正整数中与$n$互质的数的数目. 性质 1.积性函数(证明). 2.$\varphi(1)=1$(显然) 3.对于质数$n$,$\varph ...
- G 唐纳德与子串(easy)(华师网络赛---字符串,后缀数组)(丧心病狂的用后缀自动机A了一发Easy)
Time limit per test: 1.0 seconds Memory limit: 256 megabytes 子串的定义是在一个字符串中连续出现的一段字符.这里,我们使用 s[l…r] 来 ...
- github 在线 创建文件夹
参考: http://webapps.stackexchange.com/questions/36411/create-a-folder-in-github-via-the-web-interface
- python中如何定义main方法
我们有时写的python模块需要自己测试, 简单方法就是定义main函数, 然后测试自己的模块接口. def main(): test_yourCode() if __name__ == & ...