【大数据开发】Java语言基础——多线程的概念、实现多线程day19

一、多线程的概念

进程:指的是正在进行中的程序。每个进程都会占据一定的内存大小
线程:指的是负责程序执行的一条执行路径,也称为一个执行单元。进程的执行实际是线程在执行。
(1)一个进程至少有一个线程,当一个进程有多个线程时,就是一个多线程程序
(2)当一个进程中的所有线程全部执行完,进程才结束。

(3)多线程程序一定能提高效率吗?不一定,但是肯定能实现。
在同一个程序同时执行不同的功能或相同功能的效果。

(4)Java程序是不是多线程的?
至少有一个负责程序的线程,这个线程执行的是main中的代码,还需要有一个垃圾回收程序,这个线程执行的是Object类中finalize()方法中的代码(任何一个代码都能被回收,那么回收的代码应该写在Object中)

(5)线程的功能的不同,那么线程执行代码的所在位置肯定不同。

(6)线程的任务:线程执行的代码。线程的功能不同,其任务代码的位置就不同。
主线程的任务代码在main方法中,垃圾回收线程的任务代码在finalize方法中
线程是随着任务代码的执行完成而结束。

class Test
{
   public void finalize()
	{
		System.out.println("被回收了....");
	}
}

class Demo7 
{
	public static void main(String[] args)//主线程 :负责执行main中的代码
	{
		new Test();//垃圾回收线程,负责回收垃圾
		new Test();
		new Test();

        System.gc();//运行垃圾回收  守护线程
	}
}

二、实现多线程

让两个线程争抢CPU,谁抢到谁执行自己的任务代码

(1)创建线程的第一种方式——继承Thread类创建线程类(不能再继承其他类了)

1.创建一个Thread类的子类
2.重写Thread类中的run方法
------线程有其任务代码,run方法就是线程的任务代码的书写位置
3.创建子类的对象
------线程类的子类也是线程类,实际上就是创建了一个线程
4.启动线程
------start
创建线程时为了执行任务,任务代码需要有存储位置,run方法就是这个存储位置。因为Thread中的run方法没有实现任何功能,所以我们需要重写run()方法。
Thread类中几个重要方法
在这里插入图片描述
在这里插入图片描述
来看下面代码,创建线程

class Person extends Thread//定义线程类的同时,也定义了线程执行的任务代码
{
	private String name;

	Person(){}
	Person(String name)
	{
		this.name=name;
	}

	public void run()//任务代码
	{
		for(int i=1;i<=10;i++)
		{
			System.out.println(Thread.currentThread().getName()+"...show..."+name+","+i);
		}
	}
}
class Demo8 
{
	public static void main(String[] args) //主线程   自己创建的线程:子线程,子线程是由主线程启动的
	{
		Person huang=new Person("黄文强");//创建了一个子线程

		Person xu=new Person("许文强");//创建了一个子线程

		//启动线程
		huang.start();//线程启动了,当抢到cpu时,会自动去执行run方法中的任务代码
		xu.start();

		for(int i=1;i<=10;i++)
		{
		    System.out.println(Thread.currentThread().getName()+"...show..."+i);
		}

		//huang.show();
		//xu.show();
	}
}

(1)若写的是 **线程.run() **则表示调用的普通方法
若写的是 线程.start() 则会启动线程,并自动调用run()方法
(2)只是创建线程,而线程没有启动,则不会去抢占CPU。启动了也不一定可以立刻抢到CPU。
(3)在该代码中,子线程都是由主线程所启动。
(4)主线程的名字是main
子线程的名字是 Thread-编号 ------ 编号从0开始

package day17;
//每个线程发生异常只是线程自己的事儿,不会影响其它线程
class Person extends Thread
{
    private String name;

    Person(){}
    Person(String name)
    {
        this.name=name;
    }
    public void run()
    {
        int[] arr=new int[3];
        for(int i=1;i<=10;i++)
        {
           // System.out.println(arr[3]);
            System.out.println(Thread.currentThread().getName()+"...show..."+i);
        }
    }
}
class Demo9
{
    public static void main(String[] args)
    {
        Person huang=new Person("黄文强");

        Person xu=new Person("许文强");

        huang.start();
        xu.start();

       // int a=5/0;
    }
}

程序内存分析
在这里插入图片描述

(1)每个线程在栈中都拥有自己的内存,各自是独立的,当线程执行完自己的任务代码,就释放栈中的内存,所有的线程都执行完,主线程才会结束
(2)每个线程发生异常只是线程自己的事情,不会影响其他线程。如上面代码的5/0异常。其他线程代码依然正常执行。
在这里插入图片描述

(2)线程生命周期

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(3)卖票问题

class Ticket extends Thread  //该类既是线程类,也是任务类,该类的对象只能执行自己定义的任务
{
	private static int num=50;//资源

	public void run()
	{
		while(true)
		{
		   if(num>0)
              System.out.println(Thread.currentThread().getName()+"....sale..."+num--);
		}
	}
}
class Demo10 
{
	public static void main(String[] args) 
	{
		Ticket t1=new Ticket();
		Ticket t2=new Ticket();
		Ticket t3=new Ticket();
		Ticket t4=new Ticket();


		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

出现了一张票被卖四次的问题,因此把票定义成了static,问题解决了,但是不是所有情况都可以使用静态。

下面用第二种方式解决问题

(4)创建线程的第二种方式——实现Runnable接口

步骤
1.定义一个实现了Runnable接口的子类
2.在子类中重写run方法——run方法是任务代码书写的位置
3.创建Runnable接口的子类对象
4.创建Thread对象,把Runnable接口的子类对象作为参数传给Thread的构造方法
实现了Runnable接口的类是任务类,线程使用的是Thread,让线程执行什么任务就把那个任务传给线程,只要实现了Runnable接口的子类对象都可以传个Thread

class Ticket implements Runnable//任务类
{
	private  int num=50;//资源

	public void run()//任务代码
	{
		while(true)
		{
		   if(num>0)
              System.out.println(Thread.currentThread().getName()+"....sale..."+num--);
		}
	}
}
class Test implements Runnable
{
}
class Demo11 
{
	public static void main(String[] args) 
	{
		Ticket t=new Ticket();//任务对象
	    Thread t1=new Thread(t);//线程对象
		Thread t2=new Thread(t);
		Thread t3=new Thread(t);
		Thread t4=new Thread(t);

		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

问题:创建线程的第二种方式为什么可以解决卖票问题?
创建线程的第二种方式:只需要创建一个任务对象,也就是只有一份资源
总结
(1)把这个任务对象分别传给了4个线程对象,4个线程执行的任务是相同的,但是资源只有一份
(2)创建线程的第一种方式:创建4个线程对象,就创建了4份资源
(3)第二种方式不仅解决了卖票问题,而且更加面向对象,更加灵活,线程执行的任务不是固定不变的了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值