java线程的概念和创建

线程的概念

一个程序是一个进程,比如qq和腾讯会议,当我们运行这些软件的时候,相当于在运行一个进程。
进程中包含多个进程,多个进程相互争夺CPU资源,轮流执行任务,完成一个进程的任务。
举一个例子,我们在做Swing 窗口化界面的时候,为不同的组件添加监听器的时候,其实每个监听器相当于不同的线程。

我们在写java程序的时候,也可以自己创建线程。
创建线程一共有两种方式。
一个是继承Thread的类
另外一个是实现Runable的接口,并可以实现同一资源的多个使用。
两种也有不同的启动方式:
在这里插入图片描述在这里插入图片描述

例子:卖票的功能:

一共有5张票,需要3个卖票窗口买卖:
第一种方式

public class MyThread extends Thread{
    private int tickets=5; // 一共有5张票
    private String name;  // 窗口即线程的名字

    // 定义构造方法
    public MyThread(String name){
        this.name=name;
    }
    // 实现run方法
    @Override
    public void run() {
        super.run();
        while(tickets>0){
            tickets--;
            System.out.println(name+"卖了一张票,还有"+tickets+"张票");
        }
    }
}

主函数实现:

public class ThreadTicket {
    public static void main(String[] args) {
        MyThread mt1 = new MyThread("窗口1");
        MyThread mt2 = new MyThread("窗口2");
        MyThread mt3 = new MyThread("窗口3");
        mt1.start();
        mt2.start();
        mt3.start();
    }
}

运行结果:
窗口1卖了一张票,还有4张票
窗口1卖了一张票,还有3张票
窗口1卖了一张票,还有2张票
窗口1卖了一张票,还有1张票
窗口1卖了一张票,还有0张票
窗口3卖了一张票,还有4张票
窗口2卖了一张票,还有4张票
窗口3卖了一张票,还有3张票
窗口2卖了一张票,还有3张票
窗口2卖了一张票,还有2张票
窗口2卖了一张票,还有1张票
窗口3卖了一张票,还有2张票
窗口2卖了一张票,还有0张票
窗口3卖了一张票,还有1张票
窗口3卖了一张票,还有0张票

说明每个窗口都卖了5张票

第二种方式

public class Theadrunable implements Runnable{
    private int tickets=5;

    @Override
    public void run() {
        while (tickets>0){
            tickets--;
            System.out.println(Thread.currentThread().getName()+"卖了一张票,剩余票数为:"+tickets);
        }
    }
}

主函数调用:

public class ThreadTicket {
    public static void main(String[] args) {
        Theadrunable mt= new Theadrunable();
        Thread th1=new Thread(mt,"窗口1");
        Thread th2=new Thread(mt,"窗口2");
        Thread th3=new Thread(mt,"窗口3");

        th1.start();
        th2.start();
        th3.start();
    }
}

运行结果:
窗口1卖了一张票,剩余票数为:4
窗口1卖了一张票,剩余票数为:2
窗口1卖了一张票,剩余票数为:1
窗口2卖了一张票,剩余票数为:3
窗口3卖了一张票,剩余票数为:0

说明三个窗口一共卖了五张票
第二种是可以共同处理一个资源

线程的生命周期

在这里插入图片描述

守护线程

java的线程分为两种
前台运行的线程和后台运行的守护线程
在这里插入图片描述
在这里插入图片描述
守护线程创建是在线程的start()方法启动前:设置
thread.setDaemon(true);
来实现该线程是守护线程

线程池的概念

线程的创建是比较消耗内存的,所以我们要事先创建若干个可执行的线程放进一个“池(容器)” 里面,需要的时候就直接从池里面取出来不需要自己创建,使用完毕也不需要销毁而是放进“池”中, 从而减少了创建和销毁对象所产生的开销。

ExecutorService:线程池接口 ExecutorService pool(池名称) = Executors.常用线程池名;

常用线程池:

  • newsingleThreadExecutor :单个线程的线程池,即线程池中每次只有一个线程在工作,单线程 串行执行任务
  • newfixedThreadExecutor(n):固定数量的线程池,每提交一个任务就是一个线程,直到达到线程 池的最大数量,然后在后面等待队列前面的线程执行或者销毁
  • newCacheThreadExecutor:一个可缓存的线程池。当线程池超过了处理任务所需要的线程数,那 么就会回收部分闲置线程(一般是闲置60s)。当有任务来时而线程 不够时,线程池又会创建新的线程,当线程够时就调用池中线程。适 用于大量的耗时较少的线程任务。
  • newScheduleThreadExecutor:一个大小无限的线程池,该线程池多用于执行延迟任务或者固定周 期的任务。

示例:

一个买票的线程:

public class TicketTask1 implements Runnable {
	// 默认10张票
	private int ticket = 10;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 1; i <= 15; i++) {

			if (ticket > 0) {
				//获得当前执行线程名
				System.out.println(Thread.currentThread().getName() + "买票,剩余" + ticket--);
			} else {
				System.out.println(Thread.currentThread().getName() + "票卖完了");
				break;
			}

		}

	}

}

创建线程池:


public class TicketPool {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		/*
		 * 利用线程池创建线程
		 */
		
		//创建放5个线程的线程池
		//ExecutorService service=Executors.newFixedThreadPool(5);
		//可缓存的
		ExecutorService service=Executors.newCachedThreadPool();
		for(int i=1;i<=5;i++) {
			//执行线程
			service.execute(new TicketTask1());
		}
		
		//关闭线程池
		service.shutdown();

	}

}


生产消费者模型:

奶箱

当有奶的时候,拿出,没有奶的时候,放进去,保持一个稳定的状态

/**
 * @author:Xiao Chenglong
 * @Date:2021/5/11
 * 生产消费者模型
 * 奶箱
 **/
public class Box {
    private int milk;
    // 定义一个成员变量定义奶箱的状态
    private  boolean  state = false;

    public synchronized void put(int milk){
        if(state){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.milk=milk;
        System.out.println("送奶工将第"+this.milk+"奶放入奶箱");

        state=true;

        notifyAll();
    }

    public synchronized  void get(){
        if(!state){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("用户拿到第"+this.milk+"瓶奶");

        state=false;
        notifyAll();
    }
}

生产者

public class Producer implements Runnable{

    private  Box b;

    // 构造方法
    public Producer (Box b){
        this.b = b;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            b.put(i);
        }
    }
}

消费者

public class Customer implements Runnable{
    private Box b;

    public Customer(Box b) {
        this.b=b;
    }

    @Override
    public void run() {
        while (true){
            b.get();
        }
    }
}

测试类

public class BoxDemo {


    public static void main(String[] args) {
        // 创建奶箱对象
        Box box = new Box();

        // 创建生产对象
        Producer p = new Producer(box);

        // 创建消费对象
        Customer c = new Customer(box);

        // 创建线程对象
        Thread t1 = new Thread(p,"生产者");
        Thread t2 = new Thread(c,"消费者");

        // 启动线程
        t1.start();
        t2.start();

    }
}

总结

  1. 介绍了线程的简单概念
  2. 线程的两种创建方式以及具体实现(利用买车票的概念)
  3. 线程的生命周期
  4. 守护线程的概念以及设置
  5. 线程池的概念和简单应用
  6. 经典的生产消费者模型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖大仙~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值