java多线程

目录

多线程的实现方式

多线程的第一种实现方式  继承Thread类的方式进行实现

多线程的第二种实现方式  实现Runnable接口的方式进行实现

利用Callable接口和Future接口方式实现 

多线程中常用的成员方法 

String getName()                返回此线程的名称

void setName(String name)                设置线程的名字(构造方法也可以设置名字) 

static Thread currentThread()                获取当前线程的对象

static void sleep(long time)                让线程休眠指定的时间,单位为毫秒

setPriority(int newPriority)        设置线程的优先级

final int getPriority()  获取线程的优先级

final void setDaemon(boolean on)                设置为守护线程

public static void yield()                出让线程/礼让线程

public static void join()        插入线程/插队线程

线程的生命周期 

同步代码块

同步方法


javajava

Java多线程

Java多线程是指在Java语言中使用多个线程实现并发执行的编程技术。Java多线程可以提高程序的并发处理能力,使程序能够同时执行多个任务。

Java多线程可以通过创建Thread类的实例或者实现Runnable接口来实现。创建线程的方式有两种:继承Thread类和实现Runnable接口。

继承Thread类的方式创建线程,需要重写Thread类的run()方法,并在run()方法中实现线程的具体逻辑。然后创建Thread类的实例,并调用start()方法来启动线程。

实现Runnable接口的方式创建线程,需要实现Runnable接口的run()方法,并在run()方法中实现线程的具体逻辑。然后创建Thread类的实例,并将实现了Runnable接口的对象作为参数传递给Thread类的构造方法,最后调用start()方法来启动线程。

Java多线程还可以通过使用线程池来管理线程,线程池可以重复利用已创建的线程,避免频繁创建和销毁线程的开销。

在Java多线程编程中,需要注意线程的同步和互斥。可以使用synchronized关键字或者Lock接口来实现线程的同步,防止多个线程同时访问共享数据导致的数据不一致或者出错的问题。

Java多线程还提供了一些线程间通信的机制,如使用wait()和notify()方法实现线程的等待和唤醒,使用join()方法等待线程执行完成等。

总之,Java多线程可以实现并发执行的编程,提高程序的处理能力,但同时也需要注意线程的同步和互斥以及线程间的通信。

多线程的实现方式

多线程的第一种实现方式  继承Thread类的方式进行实现

自己定义一个类经承Thresd,重写run方法,创建子类的对象,并启动线程

MyThread类 

package threadcase1;

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

测试类

package threadcase1;

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

可以看到两个线程交替进行 

多线程的第二种实现方式  实现Runnable接口的方式进行实现

先写MyRun类

package threadcase2;

public class MyRun implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            //获取当前线程对象
            Thread t = Thread.currentThread();
            System.out.println(t.getName()+"hello world");
        }
    }
}

 测试类

package threadcase2;

public class ThreadDemo {
    public static void main(String[] args) {
        //创建MyRun对象
        MyRun mr = new MyRun();
        //创建线程对象
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);
        //给线程设置名字
        t1.setName("线程1");
        t2.setName("线程2");
        //开启线程
        t1.start();
        t2.start();
    }
}

 

利用Callable接口和Future接口方式实现 

创建一个类MyCallable实现callable接口重写call(是有返回值的,表示多线程运行的结果)

创建MyCallable的对象(表示多线程要执行的任务)

创建FutureTask的对象(作用管理多线程运行的结果)

创建Thread类的对象,并启动(表示线程) 

MyCallable类

package threadcase3;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i <= 100; i++) {
                sum=sum+i;
        }
        return sum;
    }
}

 测试类

package threadcase3;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建MyCallable的对象(表示多线程要执行的任务)
        MyCallable mc = new MyCallable();
        //创建FutureTask的对象(作用管理多线程运行的结果)
        FutureTask ft = new FutureTask<>(mc);
        //创建Thread类的对象,并启动(表示线程)
        Thread t1 = new Thread(ft);
        //启动线程
        t1.start();
        //获取多线程运行的结果
        Object result = ft.get();
        System.out.println(result);
    }
}

 

继承Thread类 优点:编程比较简单,可以直接使用Thread类中的方法
                        缺点:可以扩展性较差,不能再继承其他的类 

实现Runnable接口    优点: 扩展性强实现该接口的同时还可以继承其他的类

                                缺点:编程相对复杂,不能直接使用Thread类中的方法

实现Callable接口     优点:  扩展性强实现该接口的同时还可以继承其他的类

                                缺点:编程相对复杂,不能直接使用Thread类中的方法

想要获取多线程运行的结果就用Callable接口的方法 

多线程中常用的成员方法 

String getName()                返回此线程的名称
void setName(String name)                设置线程的名字(构造方法也可以设置名字)
static Thread currentThread()                获取当前线程的对象

static void sleep(long time)                让线程休眠指定的时间,单位为毫秒

setPriority(int newPriority)        设置线程的优先级

final int getPriority()  获取线程的优先级
final void setDaemon(boolean on)                设置为守护线程
public static void yield()                出让线程/礼让线程
public static void join()        插入线程/插队线程

String getName()                返回此线程的名称

 

如果我们没有给线程设置名字,线程也是有默认的名字的格式:Thread-x(X序号,从0开始的) 

void setName(String name)                设置线程的名字(构造方法也可以设置名字) 

如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置 

 

static Thread currentThread()                获取当前线程的对象

package Threadmethod;

public class ThreadDemo {
    public static void main(String[] args) {
       
        Thread t = Thread.currentThread();
        String name = t.getName();
        System.out.println(name);
    }
}

 

当JVM虚拟机启动之后,会自动的启动多条线程其中有一条线程就叫做main线程他的作用就是去调用main方法,并执行里面的代码 

static void sleep(long time)                让线程休眠指定的时间,单位为毫秒

package Threadmethod;

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {

        System.out.println("111111");
        Thread.sleep(3000);
        System.out.println("222222");
    }
}

哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间

方法的参数:就表示睡眠的时间,单位毫秒

当时间到了之后,线程会自动的醒来,继续执行下面的其他代码

setPriority(int newPriority)        设置线程的优先级

坦克的优先级比飞机的高,但是飞机比坦克先执行完成,优先级不是绝对的,是概率问题

final int getPriority()  获取线程的优先级

 

final void setDaemon(boolean on)                设置为守护线程

 

当其他的非守护线程执行完毕之后,守护线程会陆续结束 

public static void yield()                出让线程/礼让线程

 

会让结果尽可能的均匀一些,但不是绝对的 

public static void join()        插入线程/插队线程

下面的就是插入线程👇

线程的生命周期 

线程的生命周期包括新建、就绪、运行、阻塞和死亡五种基本状态。线程是程序执行的最小单元,也是操作系统分配处理器时间的基本单位。在Java等现代编程语言中,线程的生命周期涵盖了从创建到终止的全过程。为了完整理解这一周期,具体介绍如下:

1. 新建状态:“新建”是指线程对象被创建后的状态。例如,通过new关键字创建一个Thread实例时,线程就处于新建状态。此时,线程对象已被初始化,但还未开始执行。
2. 就绪状态:“就绪”是指线程已经准备好执行,等待系统分配处理器的时间片。当线程对象的start()方法被调用后,线程就会进入就绪状态。这时,线程加入到可运行池中,但尚未获得CPU的时间片,因此没有实际执行。
3. 运行状态:“运行”是指线程真正获得CPU时间片并开始执行其代码的状态。一旦就绪状态的线程被操作系统调度器选中,就会进入运行状态。在运行状态下,线程会执行其run()方法中的代码。
4. 阻塞状态:“阻塞”是指线程因某些原因暂时停止执行,进入等待状态,直到特定条件满足后才能继续执行。阻塞的常见原因包括等待I/O操作完成、等待获取锁或者显式地调用了sleep()、wait()、join()等方法。在这些情况下,线程会释放CPU资源,等待状态解除后再回到就绪或运行状态。
5. 死亡状态:“死亡”是线程完成其任务后终止的状态。线程正常完成运行(即run()方法执行完毕),或者因为异常而提前退出,都会进入死亡状态。一旦线程死亡,它就不再运行,不能再次激活。

综上所述,线程的生命周期包括新建、就绪、运行、阻塞和死亡这五个主要阶段。了解这些阶段及其转换机制,对于掌握并发编程至关重要。在多线程编程中,开发者需要合理管理线程的状态和转换,以确保程序的正确性和高效性。

     ┌─────────────────────┐
    │       新建(New)      │
    └─────────────────────┘
            │
            │ start()
            │
            ▼
    ┌─────────────────────┐
    │     就绪(Runnable)  │
    └─────────────────────┘
            │
            │ 获得CPU资源
            │
            ▼
    ┌─────────────────────┐
    │       运行(Running)  │
    └─────────────────────┘
            │
            │ 执行run()方法
            │
            ▼
    ┌─────────────────────┐
    │         阻塞(Blocked)        │
    └─────────────────────┘
            │
            │ 等待条件满足
            │
            ▼
    ┌─────────────────────┐
    │     就绪(Runnable)  │
    └─────────────────────┘
            │
            │ 再次获得CPU资源
            │
            ▼
    ┌─────────────────────┐
    │       运行(Running)  │
    └─────────────────────┘
            │
            │ 执行run()方法完成或异常
            │
            ▼
    ┌─────────────────────┐
    │       死亡(Terminated)  │
    └─────────────────────┘

同步代码块

某电影院目前正在上映国产大片,共有100张票,而它有3个窗口票,请设计一个程序模拟该电影院卖票

 

这样的话会发现与我们想要的结果不一样

 这个时候我们就可以把操作共享数据的代码锁起来

synchronized(锁){

操作共享数据的代码

锁默认打开,有一个线程进去了,锁自动关闭
里面的代码全部执行完毕,线程出来,锁自动打开

package Threadmethod;

public class MyThread3 extends Thread{
    static int ticket=0;
    //锁对象一定是唯一的
    static Object obj=new Object();
    @Override
    public void run() {
        while (true){
            //同步代码块
              synchronized (obj){
                  if (ticket<100){
                      try {
                          Thread.sleep(10);
                      } catch (InterruptedException e) {
                          throw new RuntimeException(e);
                      }
                      ticket++;
                      System.out.println(getName()+"正在售卖第"+ticket+"张票");
                  }else {
                      break;
                  }
              }
        }
    }
}

 

同步方法

MyRunable类:

package Threadmethod;

public class MyRunable implements Runnable {
    static int  ticket = 0;
    @Override
    public void run() {
        while (true){
            //同步代码块
            if(method())
                break;
        }
        }
        public synchronized  boolean method(){
        //判断共享数据是否到了末尾,如果到了末尾
            if (ticket==100){
                return true;
            }else {
                //判断共享数据是否到了末尾,如果没有到末尾
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                ticket++;
                System.out.println(Thread.currentThread().getName()+"正在售卖第"+ticket+"张票");
            }
            return false;
        }
    }

测试类

package Threadmethod;

public class ThreadDemo7 {
    public static void main(String[] args) {
        MyRunable mr=new MyRunable();
       Thread t1=new Thread(mr);
       Thread t2=new Thread(mr);
       Thread t3=new Thread(mr);

        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

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


这一期就先到这里啦,努力遇见更好的自己!!!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力敲代码的小火龙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值