Day48线程,线程安全,线程池***

进程

  • (1)进程的本质就是程序
  • (2)程序安装在硬盘上,此时不是进程
  • (3)程序加载在内存中,且正在运行,此时是进程

线程介绍

  • (1) 进程:是正在运行的应用程序
    线程:是进程中的执行单元,每一个线程可以去执行一个任 务
  • (2) 多线程程序同时可以执行多个任务
  • (3)单线程程序同时只能执行一个任务
    在这里插入图片描述

并发与并行

在这里插入图片描述

多线程程序的实现

  • (1)多线程实现步骤
    1.创建一个类,继承Thread
    2.重写Thread类中的方法
    3.在测试类中创建Thread的子类对象
    4.调用start启动线程
  • (2)当通过一个线程调用start方法后,会做两件事情
    1.这个线程会启动
    2.这个线程会自动执行自己的run方法
//1:创建Thread子类
class Thread1 extends Thread{
    @Override
    public void run() {
        //2: 重写run方法,方法内的代码需要cpu时间执行
        //存放代码
        for (int i = 0; i < 100; i++) {
            System.out.println("循环1 i =  "+i);
        }

    }
}
class Thread2 extends Thread{
    @Override
    public void run() {
        for (int j = 0; j < 100; j++) {
            System.out.println("循环2 j =  "+j);
        }
    }
}
public class Demo01 {
    public static void main(String[] args) {
        //3:创建线程对象
        Thread1 t1 = new Thread1();
        Thread2 t2 = new Thread2();

        //4 必须使用start来启动线程
        t1.start();//将run里面先放进新的线程中,再抢cpu时间,再执行
        t2.start();
        

    }
}

在这里插入图片描述

main线程介绍

  • (1)main线程
    主线程
  • (2)什么时候产生main线程
    当程序启动时,JVM会创建一个main线程,并执行程序中的main方法
  • (3)在java中有一个类表示线程,这个类叫做Thread
public class Demo02 {
    public static void main(String[] args) {
        //JVM先找到main,将main方法内的代码放到mainThread去执行
        for (int i = 0; i < 10; i++) {
            System.out.println("循环:"+i);
        }
    }
}

getName与setName

  • (1)构造方法
    Thread(String name):线程传递一个名字
  • (2)设值与取值方法
    void setName(String name) 给线程设置名字
    String getName();获取线程的名字
class Thread1 extends Thread{
    public Thread1(String name) {
        super(name);//super()调用父类的构造方法
    }

    @Override
    public void run() {
        //2: 重写run方法,方法内的代码需要cpu时间执行
        //调用setName修改线程的名称
        //super.setName("线程1号");
        System.out.println(super.getName());//获取线程的名称
        //存放代码
        for (int i = 0; i < 100; i++) {
            System.out.println("循环1 i =  "+i);
        }

    }
}

获取当前线程

  • (1)static Thread currentThread() 获取正在执行的线程对象
  • (2)Thread t = Thread.currentThread();//返回一个Thread
    如果是在主线程执行,则返回主线程
    否则返回子线程
    在这里插入图片描述

休眠

  • (1)static void sleep(long mills) 线程休眠指定的毫秒
    1 秒=1000毫秒
  • (2)//休眠5秒
    Thread.sleep(5*1000);
public class Demo03Clock {
    public static void main(String[] args) throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd hh:MM:ss");

        while (true) {   //等等1秒
            Thread.sleep(1 * 1000);
            //打印时间
            System.out.println(format.format(new Date()));

        }
    }
}

Thread的第二种实现方式

  • (1)创建线程的方式有两种
    1.子类的方式:继承Thread 重写run
    2.实现类的方式:实现Runnable 再把实现类对象给Thread对象
  • (2)Runnable接口
    实现类一般叫做线程任务类,因为里面定义的是线程要执行的任
  • (3)JVM只有看到Thread才知道是线程
  • (4)实现步骤
    1.定义类,然后实现Runnable接口
    2.重写这个接口中的run方法,在run方法中定义线程要执行的任务
    3.在测试类中创建Runnable实现类对象
    4.创建Thread对象,并且在构造方法位置传递Runnable实现类对象
    5.调用线程的start方法,开启线程,线程会执行对应的run方法
//1 实现类的方式:Runnable
class Task1 implements Runnable{
    @Override
    public void run() {
        //2:执行代码
        for (int i = 0; i < 100; i++) {
            System.out.println("循环1 i =  "+i);
        }

    }
}
class Task2 implements Runnable{
    @Override
    public void run() {

        for (int j = 0; j < 100; j++) {
            System.out.println("循环2 j =  "+j);
        }
    }
}
public class Demo04 {
    public static void main(String[] args) {

        //JVM只看Thread
        Task1 task1 = new Task1();
        Task2 task2 = new Task2();
        //为后续线程池做准备
        Thread t1 = new Thread(task1);//调用Thread构造方法 Thread(Runnable r)
        Thread t2 = new Thread(task2);
        t1.start();
        t2.start();
    }
}

第二种实现方式的好处***

  • (1)第二种方式更好
    1.实现接口的方式解决了java类中类与类之间
    单继承的局限性
    2.Runnable 接口中只有一个 run方法,没有start,setName,getName,这些方法,在Runnable接口中只需要关注线程要执行的任务,这样的话,功能更加的纯粹,更加符合设计模式中的单一职责原则
    3.降低耦合性
    4.第二种方式可以更加简便的实现多个线程之间的数据共享,线程池

同步代码块解决线程安全问题

在这里插入图片描述

  • (1)解决线程安全问题的关键是 多线程写共享数据时,让线程排队
  • (2)可以使用同步关键字或者锁
  • (3)分析上厕所

JDK1.5之后的Lock锁

  • (1)在jdk1.5之后,提供了Lock接口,这个Lock接口表示的是锁,支持手动的获取锁以及手动的释放锁
    Lock是一个接口,如果要用需要使用它的实现类
    我们可以使用实现类 ReentrantLock
  • (2)
    void lock():手动的获取锁
    void unlock():手动的释放锁
  • (3)同步方法和同步代码块的好处
    1.同步方法:语法简洁
    2.同步代码块:更加灵活
  //加锁
            lock.lock();
            //如果票数> 0 ,退出
            if (tikets > 0) {
                tikets--;
                System.out.println("还剩余" + tikets + "张");
            }else{
                break;
            }
            //释放锁
            lock.unlock();
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

翁老师的教学团队

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

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

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

打赏作者

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

抵扣说明:

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

余额充值