参考:http://lavasoft.blog.51cto.com/62575/99150

http://blog.csdn.net/baby_newstar/article/details/6783752

http://www.runoob.com/java/java-multithreading.html

1.操作系统中的进程和线程

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

2.java中的线程

一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。

其他线程通过使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。

线程又分用户线程和守护线程。只有通过设置setDaemon(true)的线程才是守护线程。用户线程的生命周期由该线程自定义,比如while(true)一直执行。守护线程的生命周期是由创造它的线程决定的,父线程死掉了,它也就立即死亡而不管是否有任务还没有执行。抽象的理解就是:守护线程是工蜂,蜂后死掉后也会跟着死掉。

3.线程的生命周期

  • 新建状态:使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
  • 就绪状态:当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
  • 运行状态:如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
  • 阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。
  • 死亡状态:一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
  • 如图:

4.创建一个线程

Java提供了两种创建线程方法:

  • 通过实现Runable接口;
  • 通过继承Thread类本身。

1、如果是扩展java.lang.Thread类的线程,则直接new即可。

2、如果是实现了java.lang.Runnable接口的类,则用Thread的构造方法:
Thread(Runnable target) 
Thread(Runnable target, String name) 
Thread(ThreadGroup group, Runnable target) 
Thread(ThreadGroup group, Runnable target, String name) 
Thread(ThreadGroup group, Runnable target, String name, long stackSize)

4.1实现Runnable接口

package com.test.java.thread;

/**
* 学习线程
* Created by mrf on 2016/2/25.
*/
public class NewThread implements Runnable{
Thread thread;
NewThread(){
//创建第二个新线程
thread = new Thread(this,"Demo Thread");
System.out.println("我是实现Runnable接口的类,我被创建了。而且我开始创建另一个线程(name,priority,groupname):"+thread);
thread.start();
} //第二个线程入口
@Override
public void run() {
System.out.println("------------------我是实现Runnable接口的运行入口,我要开始运行了。-----------------------");
try {
for (int i = 0; i < 5; i++) {
System.out.println("Child Thread:"+i);
//暂停线程
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted");
e.printStackTrace();
}
System.out.println("---------------我这个线程就要运行结束了.------------------------"); }
} class ThreadDemo{
public static void main(String[] args) {
System.out.println("===========main线程开始运行。==============");
System.out.println("当前运行的是main线程:"+Thread.currentThread());
new NewThread();//创建一个新线程
try {
for (int i =0; i<5; i++){
System.out.println("main thread:"+i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("main thread interruped.");
e.printStackTrace();
}
System.out.println("==============main线程运行结束.================");
}
}

运行结果:

===========main线程开始运行。==============
当前运行的是main线程:Thread[main,5,main]
我是实现Runnable接口的类,我被创建了。而且我开始创建另一个线程(name,priority,groupname):Thread[Demo Thread,5,main]
main thread:0
------------------我是实现Runnable接口的运行入口,我要开始运行了。-----------------------
Child Thread:0
Child Thread:1
Child Thread:2
main thread:1
Child Thread:3
Child Thread:4
main thread:2
---------------我这个线程就要运行结束了.------------------------
main thread:3
main thread:4
Disconnected from the target VM, address: '127.0.0.1:4625', transport: 'socket'
==============main线程运行结束.================

分析:

  java程序从main线程开始,这是主线程。然后new NewThread(),创建了这个叫做NewThread的类,这个类的构造方法里面又调用了另一个线程,即从这里开始调用新线程了。main线程和新线程的优先级都为5,因此轮换使用cpu,所以才会出现交替打印的现象。

问题:上面的结果显示自线程运行结束后main线程才结束,那么子线程的生命周期和main有关吗?

答案是否定的,下面我将子线程的运行时间加长就会看到结果。

package com.test.java.thread;

/**
* 学习线程
* Created by mrf on 2016/2/25.
*/
public class NewThread implements Runnable{
Thread thread;
NewThread(){
//创建第二个新线程
thread = new Thread(this,"Demo Thread");
System.out.println("我是实现Runnable接口的类,我被创建了。而且我开始创建另一个线程(name,priority,groupname):"+thread);
thread.start();
} //第二个线程入口
@Override
public void run() {
System.out.println("------------------我是实现Runnable接口的运行入口,我要开始运行了。-----------------------");
try {
for (int i = 0; i < 5; i++) {
System.out.println("Child Thread:"+i);
//暂停线程
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted");
e.printStackTrace();
}
System.out.println("---------------我这个线程就要运行结束了.------------------------"); }
} class ThreadDemo{
public static void main(String[] args) {
System.out.println("===========main线程开始运行。==============");
System.out.println("当前运行的是main线程:"+Thread.currentThread());
new NewThread();//创建一个新线程
try {
for (int i =0; i<5; i++){
System.out.println("main thread:"+i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("main thread interruped.");
e.printStackTrace();
}
System.out.println("==============main线程运行结束.================");
}
}

结果:

===========main线程开始运行。==============
当前运行的是main线程:Thread[main,5,main]
我是实现Runnable接口的类,我被创建了。而且我开始创建另一个线程(name,priority,groupname):Thread[Demo Thread,5,main]
main thread:0
------------------我是实现Runnable接口的运行入口,我要开始运行了。-----------------------
Child Thread:0
main thread:1
main thread:2
main thread:3
main thread:4
==============main线程运行结束.================
Child Thread:1
Child Thread:2
Child Thread:3
Child Thread:4
---------------我这个线程就要运行结束了.------------------------

注意我将子线程的睡眠时间改成了500.这样,main线程执行完毕后子线程仍然继续执行。这个有点可以使我们在做业务代码时将不要紧的代码多线程异步执行,优化运行体验和效率。

4.2守护线程演示

还是上面的代码,我将子线程设置为守护线程,并且设置子线程运行时间>main线程,看是否main线程运行结束后守护线程直接死掉。这里注意,setDaemon一定要放在start前,因为会判断isAlive,如果活着就不能设置为守护线程了,因为已经在运行了。

package com.test.java.thread;

/**
* 学习线程
* Created by mrf on 2016/2/25.
*/
public class NewThread implements Runnable{
Thread thread;
NewThread(){
//创建第二个新线程
thread = new Thread(this,"Demo Thread");
System.out.println("我是实现Runnable接口的类,我被创建了。而且我开始创建另一个线程(name,priority,groupname):"+thread);
thread.setDaemon(true);
thread.start();
} //第二个线程入口
@Override
public void run() {
System.out.println("------------------我是实现Runnable接口的运行入口,我要开始运行了。-----------------------");
try {
for (int i = 0; i < 5; i++) {
System.out.println("Child Thread:"+i);
//暂停线程
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted");
e.printStackTrace();
}
System.out.println("---------------我这个线程就要运行结束了.------------------------"); }
} class ThreadDemo{
public static void main(String[] args) {
System.out.println("===========main线程开始运行。==============");
System.out.println("当前运行的是main线程:"+Thread.currentThread());
new NewThread();//创建一个新线程
try {
for (int i =0; i<5; i++){
System.out.println("main thread:"+i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("main thread interruped.");
e.printStackTrace();
}
System.out.println("==============main线程运行结束.================");
}
}

运行结果:

===========main线程开始运行。==============
当前运行的是main线程:Thread[main,5,main]
我是实现Runnable接口的类,我被创建了。而且我开始创建另一个线程(name,priority,groupname):Thread[Demo Thread,5,main]
main thread:0
------------------我是实现Runnable接口的运行入口,我要开始运行了。-----------------------
Child Thread:0
main thread:1
main thread:2
main thread:3
main thread:4
Child Thread:1
Disconnected from the target VM, address: '127.0.0.1:6928', transport: 'socket'
==============main线程运行结束.================

和上一个测试对比相当明显,child thread仅仅打印了一次就结束了,说明它死掉了,说明创建他的main线程死掉后,她跟着死掉。

4.3继承Thread

通过继承Thread,重写run方法来实现多线程。下面是实例,另外上面的代码写的不太清楚,start方法应该放外面来调用比较好。

package com.test.java.thread;

/**
* 多线程学习---继承Thread
* Created by mrf on 2016/2/25.
*/
public class NewThreadExtend extends Thread{
NewThreadExtend(){
//创建第二个线程
super("Demo Thread.");
System.out.println("子线程:"+this);
} //通过重写run方法来实现线程业务逻辑
public void run(){
System.out.println("-------我是子线程,我开始运行----------------");
try {
for (int i = 0; i < 5; i++) {
System.out.println("子线程:"+i);
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("子线程interrupted");
e.printStackTrace();
}
System.out.println("-------我是子线程,我结束运行----------------");
} } class ExtendThread{
public static void main(String[] args) {
System.out.println("========我是main线程,我开始运行:"+Thread.currentThread());
NewThreadExtend newThreadExtend = new NewThreadExtend();
newThreadExtend.start();
try {
for (int i = 0; i < 5; i++) {
System.out.println("main线程:"+i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("main线程interrupted.");
e.printStackTrace();
}
System.out.println("========main线程运行结束=====================");
}
}

运行结果:

========我是main线程,我开始运行:Thread[main,5,main]
子线程:Thread[Demo Thread.,5,main]
main线程:0
-------我是子线程,我开始运行----------------
子线程:0
子线程:1
main线程:1
子线程:2
子线程:3
子线程:4
main线程:2
-------我是子线程,我结束运行----------------
main线程:3
main线程:4
Disconnected from the target VM, address: '127.0.0.1:11051', transport: 'socket'
========main线程运行结束=====================

5.Thread的方法

方法就不在这里赘述了,普通方法必须由thread对象来调用,比如start,静态方法可以由Thread来调用。这里再说下start,start执行的是run方法,初学的时候会很纳闷,因为没有深入源码。好吧,我也没深入,但大概看到start是加入group,然后调用start0,start0是个native method。啥是native method?看到介绍说是调用其他语言实现的代码,到这里就是jvm干的事情了,我们不知道做了什么。不过可以猜测是和操作系统交互,获取进程资源之类的吧,然后应该回调run方法。总之,要理解start就是在执行run方法,不过start看起来像是代理而已。

public void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

6.线程的几个概念

在多线程编程时,你需要了解以下几个概念:

  • 线程同步
  • 线程间通信
  • 线程死锁
  • 线程控制:挂起、停止和恢复

7.线程同步和锁下次学习

java线程(1)--概念基础的更多相关文章

  1. Java线程:概念与原理

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  2. java 线程​基本概念 可见性 同步

    开发高性能并发应用不是一件容易的事情.这类应用的例子包括高性能Web服务器.游戏服务器和搜索引擎爬虫等.这样的应用可能需要同时处理成千上万个请求.对于这样的应用,一般采用多线程或事件驱动的架构.对于J ...

  3. Java线程:概念与使用

    Java线程大总结 原文章地址:一篇很老的专栏,但是现在看起来也感觉深受启发,知识点很多,很多线程特点我没有看,尴尬.但是还是整理了一下排版,转载一下. 操作系统中线程和进程的概念 在现代操作系统中, ...

  4. Java线程:概念与原理(转)

    一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在 ...

  5. Java - 线程基本概念

    [java并发编程实战]-----线程基本概念 线程状态图 说明:线程共包括以下5种状态.1. 新建状态(New)         : 线程对象被创建后,就进入了新建状态.例如,Thread thre ...

  6. Java线程的概念

    1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...

  7. 《Java基础知识》Java线程的概念

    按照规划,从本篇开始我们开启『并发』系列内容的总结,从本篇的线程开始,到线程池,到几种并发集合源码的分析,我们一点点来,希望你也有耐心,因为并发这块知识是你职业生涯始终绕不过的坎,任何一个项目都或多或 ...

  8. java线程的一些基础小知识

    --------------------------------------------------------------------------------------------------线程 ...

  9. Java线程问题(基础回顾)

    1.概念:线程是运行程序(进程)中单个顺序的小程序,一个进程可以由多个线程组成,而这多个线程共享同一个存储空间,这使得线程间的通信比较容易.在一个多进程的程序中,如果要切换到另一个进程,需要改变地址空 ...

随机推荐

  1. 2013-09-22 [随笔]-Roy

    不能因为一些小事情而一直影响自己的心情. 每天过得都应该有重点,无论是家庭还是工作还是其他. 要多花时间去吸取些新东西,看书,丰富自己的想法. 不能让日常的乱七八糟影响心情. bingo!

  2. SQL TRACE

    1.SQL TRACE说明: 参数类型 布尔型 缺省值 false 参数类别 动态 取值范围 True|false 2.类型 1)sql trace参数:alter system改变对全局进程影响,如 ...

  3. JavaFX結合 JDBC, Servlet, Swing, Google Map及動態產生比例圖 (2):JavaFX建立及程式碼說明 (转帖)

    說明:就如同標題一樣,前端會用到JavaFX.Swing.Java Web Start.Google Map 的技術, 後端就是JDBC.Servlet的技術,以及我們會簽署認證jar檔案,這樣才可存 ...

  4. 亚马逊云服务器VPS Amazon EC2 免费VPS主机配置CentOS及其它内容

    Amazon目前提供为期一年的免费VPS服务,可到地址http://aws.amazon.com 进行申请. 现在对账号申请成功后,对VPS主机配置CentOS的过程做个图文介绍 1.创建实例(Ins ...

  5. .Net平台下,分布式文件存储的实现

    遇到的问题 对于Web程序,使用一台服务器的时候,客户端上传的文件一般也都是存储在这台服务器上.但在集群环境中就行不通了,如果每个服务器都存储自己接受到的文件,就乱套了,数据库中明明有这个附件的记录, ...

  6. [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现

    一.引言 在上一专题中,商家发货和用户确认收货功能引入了消息队列来实现的,引入消息队列的好处可以保证消息的顺序处理,并且具有良好的可扩展性.但是上一专题消息队列是基于内存中队列对象来实现,这样实现有一 ...

  7. 作业七:团队项目——Alpha版本冲刺阶段-11

    部分功能实现: public void actionPerformed(ActionEvent ae) { //重新开始按钮 if (ae.getSource().equals(anew)){ int ...

  8. 【MVC】bootstrap-paginator 分页插件笔记

    bootstrap-paginator基于bootstrap框架,使用起来非常简单.github地址:https://github.com/lyonlai/bootstrap-paginator 在b ...

  9. 手把手搭建WAMP+PHP+SVN开发环境

    一:WAMP 这款软件在安装的过程中就已经把Apache.MySQL.PHP继承好了,而且也做好了相应的配置,除此之外,还加上了SQLitemanager和Phpmyadmin,省去了很多复杂的配置过 ...

  10. Chrome扩展程序的二次开发:把它改得更适合自己使用

    我当然知道未经作者允许修改别人程序是不道德的了,但作为学习研究之用还是无可厚非,这里仅供交流. 一切都是需求驱动的 话说某天我在网上猎奇的时候无意间发现这么一款神奇的谷歌浏览器插件:Extension ...