JAVA基础--多线程

(一)多线程

基本概念

  1. 并行:同时进行
    并发:交替进行

  2. 硬盘:永久存储
    内存:应用程序都要进入内存中执行 临时存储RAM

  3. 进程:进入内存的程序
    线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。 一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

    简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

thread多线程原理

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

thread类

构造方法:

  • public Thread() :分配一个新的线程对象。
  • public Thread(String name) :分配一个指定名字的新的线程对象。
  • public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
  • public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

常用方法:

  • public String getName() :获取当前线程名称。

  • public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

  • public void run():此线程要执行的任务在此处定义代码

  • public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

  • public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

创建新线程的方法一

通过继承Thread类来创建并启动多线程的步骤如下:
1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任
务,因此把run()方法称为线程执行体。
2. 创建Thread子类的实例,即创建了线程对象
3. 调用线程对象的start()方法来启动该线程

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("run"+i);
        }

    }
}
MyThread mt=new MyThread();
        mt.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("main"+i);
        }

创建新线程的方法二

1.创建Runnable的实现类,重写run()方法
2.创建Runnable实现类对象
3.创建Thread对象,构造方法中传递Runnable的实现类对象
4.调用Thread类中的start()方法,开启新线程执行run()方法

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }


    }
RunnableImpl runnable=new RunnableImpl();
        Thread t=new Thread(runnable);
        t.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }

两者区别

实现Runnable接口创建多线程程序的好处
1.避免了单继承的局限性
一个类只能继承一个类,类继承了Thread类就不能继承其他的类
实现了Runnable接口,还可以实现其他的接口
2.增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnanle接口的方式,把设置线程任务和开启新线程进行了分离(解耦):实现类中,重写了run()方法,用来设置线程任务;创建Thread对象,调用start()方法,来开启新线程

匿名内部类实现线程的创建

在这里插入图片描述

		//Tread类方式
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        }.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
        
        //Runnable接口的方式
        Runnable rb=new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        };
        new Thread(rb).start();

        //简化代码
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        }).start();

(二)线程安全

1.线程同步三种解决方式

1.同步代码块。
2.同步方法。
3.锁机制。

2.同步代码块

Object obj=new Object();//创建锁对象
synchronized ( 同步锁obj ) {
需要同步操作的代码
}

1.锁对象可以是任意类型。
2.多个线程对象要使用同一把锁。
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED)。
·当一个线程进入代码块时,拿到所对象方可执行代码块内容,执行完代码块内容归还锁对象;若锁对象不在,则须等待上个线程归还锁对象并拿到锁对象才可进入代码块。此举实现同步。

3.锁机制

·Lock 接口:
void lock();加同步锁
void unlock();释放同步锁
Reentrantlock():Lock接口的实现类对象

4.同步方法

public synchronized void method(){
可能出现问题的代码
}
·非静态方法,同步锁就是this
`静态方法,同步锁就是当前方法所在类的字节码对象(类.class)

(三)线程状态

NEW(新建) 线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
Blocked(锁阻塞) 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待) 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
TimedWaiting(计时等待) 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法Thread.sleep 、Object.wait。
Teminated(被终止) 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

  1. Timed Waiting在API中的描述为:一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态。
    其实当我们调用了sleep方法之后,当前执行的线程就进入到“休眠状态”,其实就是所谓的Timed Waiting(计时等待)

在这里插入图片描述

sleep方法的使用还是很简单的。我们需要记住下面几点:

  1. 进入 TIMED_WAITING 状态的一种常见情形是调用的 sleep 方法,单独的线程也可以调用,不一定非要有协 作关系。
  2. 为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程 中会睡眠
  3. sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。 小提示:sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就 开始立刻执行。
  1. Blocked状态在API中的介绍为:一个正在阻塞等待一个监视器锁(锁对象)的线程处于这一状态。
    比如,线程A与线程B代码中使用同一锁,如果线程A获取到锁,线程A进入到Runnable状态,那么线程B就进入到Blocked锁阻塞状态。
  2. Wating状态在API中介绍为:一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程处于这一状态。
    `

买包子示例:顾客告诉老板买什么包子,等待等老板做包子;老板做好之后,顾客拿走自己的包子。
创建顾客线程和老板线程,等待即顾客这个线程保持waiting状态,老板线程执行,执行完后调用notify()唤醒waiting状态。

Object obj =new Object();
        //顾客线程
        new Thread(){
            @Override
            public void run() {
                //同步
                synchronized (obj){
                    System.out.println("顾客下单包子的数量和种类");
                    try {
                        obj.wait();//等待机制
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("顾客拿到自己的包子");

                }
            }
        }.start();
        //老板线程
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (obj){
                    System.out.println("您的包子好了!小心烫~");
                    obj.notify();//唤醒机制
                }

            }
        }.start();
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值