java线程(1)--概念基础

参考: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.线程同步和锁下次学习

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java技术栈

一个多线程死锁案例,如何避免及解决死锁问题?

多线程死锁在java程序员笔试的时候时有遇见,死锁概念在之前的文章有介绍,大家应该也都明白它的概念,不清楚的去翻看历史文章吧。 下面是一个多线程死锁的例子 输出...

2847
来自专栏iOS Developer

Bison眼中的iOS开发多线程是这样的(二)

1193
来自专栏专注 Java 基础分享

Java并发之线程中断

     前面的几篇文章主要介绍了线程的一些最基本的概念,包括线程的间的冲突及其解决办法,以及线程间的协作机制。本篇主要来学习下Java中对线程中断机制的实现。...

2009
来自专栏我是攻城师

理解Java并发工具类CountDownLatch

CountDownLatch相信大家并不陌生,我们在上篇文章中已经分析其实现,这里在简单回顾一下CountDownLatch是基于AQS共享锁构建的一种同步器,...

1005
来自专栏Java Web

《编写高质量代码》学习笔记(3)

建议125:优先选择线程池 在Java1.5之前,实现多线程比较麻烦,需要自己启动线程,并关注同步资源,防止出现线程死锁等问题,在1.5版本之后引入了并行计算框...

3385
来自专栏java架构师

BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock

继续面试大纲系列文章。   这是多线程的第二篇。   多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生;而滥用则会遭其反噬。   在多线程...

35111
来自专栏Java帮帮-微信公众号-技术文章全总结

Java多线程详解1

Java多线程详解 ? ? ? ? Java线程:概念与原理 一、操作系统中线程和进程的概念 现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。 进...

3959
来自专栏java思维导图

【一分钟知识】线程同步,线程调度

sleep()和yield()方法区别 1 sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会; yield()方法只...

3178
来自专栏chenssy

【死磕Java并发】—–J.U.C之并发工具类:CyclicBarrier

CyclicBarrier,一个同步辅助类,在API中是这么介绍的: 它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point...

3234
来自专栏林冠宏的技术文章

java 线程 Thread 使用介绍,包含wait(),notifyAll() 等函数使用介绍

(原创,转载请说明出处!谢谢--https://cloud.tencent.com/developer/user/1148436/activities)  此文...

1837

扫码关注云+社区