java基础24 线程、多线程及线程的生命周期(Thread)

1.1、进程

正在执行的程序称作为一个进程.进程负责了内存空间的划分

 疑问1:windows电脑称之为多任务的操作系统,那么Windows是同时运行多个应用程序呢?
从宏观的角度:windows确实在同时运行多个程序.
从微观的角度:cpu是做一个快速的切换执行的动作,速度太快,所以你感觉不到切换而已.

1.2、线程

线程在一个进程中负责了代码的执行,进程中的一个执行路径

1.3、多线程

在一个进程中有多个线程同时在执行不同的任务

疑问2:线程负责了代码的执行,我们之前没有学过线程,为什么代码可以执行?
任何一个java程序,在jvm运行时都会创建一个main线程执行main方法中的所有代码.

1.4、多线程好处

1.解决一个进程中能执行多个任务的问题.
    2.提高了资源的利用率

1.5、多线程弊端

1.增加了cpu的负担
    2.降低了一个进程中的线程执行的概率
    3.引发了线程安全问题
    4.出现死锁的现象

1.6、创建多线程的方式

方式一:
    1.自定义一个类继承Thread类
    2.重写Thread的类里面的run方法,自定义线程的代码写在run方法里面
    3.创建Thread的子类对象,并且调用start方法开启线程.

注意:一个线程一旦开启,那么这个线程就会执行run方法中的代码,run方法千万不要直接调用,如果直接调用它就相当于一个普通方法,就不会开启新的线程。

疑问3: 重写run方法的目的是什么?
每个线程都有自己的任务代码,jvm创建主线程的任务代码就是main方法中的所有代码,自定义线程的任务代码,需要写在run方法里面,自定线程负责run方法中的代码

方式二:
    1.自定义一个类实现Runnable接口
    2.实现Runnable里面的run方法,把自定义线程的任务定义在run方法里面
    3.创建Runnable实现类对象
    4.创建Thread对象,并且把Runnable实现类对象作为参数传递
    5.调用Thread对象的start方法开启一个线程

推荐使用:第二种 实现Runnable接口的方式;因为java单继承,多实现

问题4:请问Runnable实现对象是线程对象吗?
答:Runnable实现类对象并不是一个线程对象,只不过实现了Runnable接口的对象而已,只有Thread或者Thread的子类才是线程对象
问题5:为啥要把Runnable实现类对象作为参数传递给Thread对象呢?作用是什么?
答:作用就是把Runnable实现类对象的run方法作为线程的任务代码去执行了.

1.7、实例

 package com.zn.thread;

 /**
* @author DSHORE / 2018-5-3
* 方式1的实例
*/
/*创建多线程的方式
* 方式一:
* 1.自定义一个类继承Thread类
* 2.重写Thread的类里面的run方法,自定义线程的代码写在run方法里面
* 3.创建Thread的子类对象,并且调用start方法开启线程.
*
* 注意:一个线程一旦开启,那么这个线程就会执行run方法中的代码,run方法千万不要直接调用,如果直接调用它就相当于一个普通方法,就不会开启新的线程.
*
* */
public class Demo1 extends Thread {//1.自定义一个类继承Thread类
@Override
public void run() {//2.重写Thread的类里面的run方法,自定义线程的代码写在run方法里面
for(int i=;i<;i++){
System.out.println("自定义线程"+i);
}
}
public static void main(String[] args) {
Demo1 d=new Demo1();//3.创建Thread的子类对象,并且调用start方法开启线程.
d.start(); for(int i=;i<;i++){
System.out.println("主线程"+i);
}
}
}

运行结果图: 注:每次的运行结果都不一样,线程问题

java基础24 线程、多线程及线程的生命周期(Thread)

 package com.zn.thread;

 /**
* @author DSHORE / 2018-5-3
* 方式2的实例
*/
/*方式二:
* 1.自定义一个类实现Runnable接口
* 2.实现Runnable里面的run方法,把自定义线程的任务定义在run方法里面
* 3.创建Runnable实现类对象
* 4.创建Thread对象,并且把Runnable实现类对象作为参数传递
* 5.调用Thread对象的start方法开启一个线程
*
* 推荐使用:第二种 实现Runnable接口的方式;因为java单继承,多实现
*/
class Test implements Runnable{ @Override
public void run() { for(int i=;i<;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Demo2 { public static void main(String[] args) {
//创建Runnable实现类对象
Test t=new Test();
//创建Thread对象,并且把Runnable实现类对象作为参数传递
Thread d=new Thread(t,"二狗子");
//调用Thread对象的start方法开启一个线程
d.start();
for (int i = ; i <; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}

运行结果图

java基础24 线程、多线程及线程的生命周期(Thread)

1.8、线程的生命周期 图解

java基础24 线程、多线程及线程的生命周期(Thread)

线程生命周期的五种状态:

    1、新建(new Thread):当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值

    2、就绪(runnable)当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行

    3、运行(running)如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态

    4、堵塞(blocked)当处于运行状态的线程失去所占用资源之后(正在运行的线程让出CPU并暂停自己的执行),便进入阻塞状态

    5、死亡(dead)线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

线程生命周期详解:https://www.cnblogs.com/sunddenly/p/4106562.html  或  https://blog.csdn.net/pange1991/article/details/53860651

下面是:wait()、notify()、notifyAll()、interrupt()、setDaemon()、join() 等方法的使用

 package com.zn.thread;

 /*
* 线程的通讯:一个线程完成了自己的任务时,要通知另一个线程去完成另一个任务
*
* 生产者与消费者
*
* wait():等待。如果线程执行到了wait方法,那么该线程会进入等待状态,等待状态下的线程必须要被其他线程调用notify()方法才能唤醒.
* notify():唤醒。唤醒线程池等待的其中一条线程
* notifyAll(): 唤醒线程池中所等待的线程
* */
//产品
class Product{
String name;//产品名字
double price;//价格
boolean flag=false;//生产者是否生产完成的标志,默认是没有生产完成
}
//生产者
class Producer extends Thread{
Product p;
public Producer(Product p) {
this.p=p;
}
@Override
public void run() {
int i=;
while(true){
synchronized (p) {
if(p.flag==false){
if(i%==){
p.name="苹果";
p.price=5.0;
}else{
p.name="香蕉";
p.price=3.5;
}
System.out.println("生存者生产出了:"+p.name+"; 价格是:"+p.price);
p.flag=true;//flag为true时,通知消费者去消费
i++;
p.notify();//唤醒 消费者去消费
}else{
try {
p.wait();//生产者等待
} catch (InterruptedException e) {
e.printStackTrace();//打印异常信息
}
}
}
}
}
}
//消费者
class Customer extends Thread{
Product p;
public Customer(Product p) {
this.p=p;
}
@Override
public void run() {
while(true){
synchronized (p) {
if(p.flag==true){
System.out.println("消费者消费了:"+p.name+"; 价格:"+p.price);
p.flag=false;//flag为false时,通知生产者去生产
p.notify();//唤醒 生产者去生产
}else{
try {
p.wait();//消费者也等待了
} catch (InterruptedException e) {
e.printStackTrace();//打印异常信息
}
}
}
}
}
}
public class Demo5 {
public static void main(String[] args) {
Product p=new Product();
//创建线程对象
Producer producer=new Producer(p);
Customer customer=new Customer(p);
//开启线程
producer.start();
customer.start();
}
}
 package com.zn.thread;
/*停止线程:
* 1.停止一个线程 我们一般都会通过一个变量去控制
* 2.如果需要停止一个处于等待状态的线程,那么我们需要通过变量配合notify方法或者interrupt()来使用
* */
public class Demo2 extends Thread{
boolean flag=true;
public Demo2(String name) {
super(name);
}
@Override
public synchronized void run() {
int i=;
while(flag){
System.out.println("嘿,你好"+Thread.currentThread().getName()+":"+i);
i++;
}
}
public static void main(String[] args) {
Demo2 d=new Demo2("狗娃");
d.start();
System.out.println("");
for (int i = ; i <; i++) {
d.flag=false;
d.interrupt(); //interrupt():调用该方法后,该线程被置于"中断状态"
}
}
}
 package com.zn.thread;
/*
* 保护线程(后台线程):在一个进程中如果只剩下了守护线程,那么守护线程也会死亡
* 需求:模拟QQ下载更新包
*
* */
public class Demo3 extends Thread{
public Demo3(String name){
super(name);
}
@Override
public void run() {
for (int i = ; i <=; i++) {
System.out.println("更新包目前下载"+i+"%");
if(i==){
System.out.println("下载完毕");
}
}
try {
Thread.sleep();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Demo3 d=new Demo3("后台线程");
d.setDaemon(true);//将该线程标记为守护线程或用户线程,该方法必须在启动线程前调用
System.out.println(d.isDaemon());
d.start();
for (int i = ; i <=; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}

join()  方法

 package com.zn.thread;

 /**
* @author DSHORE / 2018-5-14
*
*/
/*
* join()方法:加入
*
* 需求:在没加油处插入去买酱油的过程,顺序要正确
*
* */ //老妈
class Mon extends Thread{
@Override
public void run() {
System.out.println("妈妈洗菜");
System.out.println("妈妈切菜");
System.out.println("妈妈准备炒菜,发现没酱油了");
Son s=new Son();
s.start();
try {
s.join();//加入,一个线程如果执行join语句,那么就会有新的线程加入,执行该语句的线程必须要让步给新加入的线程完成任务,然后才能继续执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("妈妈继续炒菜");
System.out.println("全家一起卡饭...");
}
}
//儿子
class Son extends Thread{
@Override
public void run() {
System.out.println("让儿子下楼去买");
System.out.println("儿子买完酱油");
System.out.println("上楼把酱油给老妈");
}
}
public class Demo8 {
public static void main(String[] args) {
Mon m=new Mon();
m.start();
}
}

运行结果图

java基础24 线程、多线程及线程的生命周期(Thread)          java基础24 线程、多线程及线程的生命周期(Thread)

原创作者:DSHORE

作者主页:http://www.cnblogs.com/dshore123/

原文出自:http://www.cnblogs.com/dshore123/p/8984060.html

欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!

上一篇:我教女朋友学编程Html系列(6)—Html常用表单控件


下一篇:第九课 表单及表单控件 html5学习4