Java之多线程的实现

进程与线程的概念

进程:操作系统中一个程序的执行周期
线程:一个进程同时执行多个任务。通常来讲,每个任务就称为一个线程。
线程与进程比较:
1.线程更加的“轻量级”,创建、撤销一个线程比启动、撤销一个进程开销要小的多。一个进程中的所有线程共享此进程的所有资源。
2.没有进程就没有线程,进程一旦终止,其内的线程也将不复存在
3.进程是操作系统资源调度的基本单位,进程可以独享资源。线程需要依托进程提供的资源,无法独立申请操作系统资源,是OS任务执行的基本单位。
高并发:访问的线程量非常非常高。
高并发带来的问题:服务器内存不够用,无法处理新的请求。

多线程实现

继承Thread类实现多线程

java.lang.Thread是线程操作的核心类。新建一个线程最简单的方法就是直接继承Thread,而后覆写run()方法(相当于主线程的main()方法,线程入口 )
线程启动一定调用Thread类提供的start()方法:public synchronized void start()此方法会自动调用线程的run()方法
范例:实现多线程

class MyThread extends Thread{
    private String title;
    public MyThread(String title){
       this.title=title;
    }
    public void run(){
        for(int i=0;i<3;i++){
            System.out.println(this.title+" "+i);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread myThread1=new MyThread("线程1");
        MyThread myThread2=new MyThread("线程2");
        MyThread myThread3=new MyThread("线程3");
        //启动线程
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}

运行结果:所有线程对象交替执行
在这里插入图片描述
看到这里相信有很多童鞋都会有一个疑问就是为什么要通过start()方法来调用run()方法,而不是run()直接执行?
来我们看start方法源码
在这里插入图片描述

  1. start方法只能调用一次,多次调用会抛出异常
  2. 下面我们看到了在start()方法中调用了start0()方法,而这个方法是一个只声明而未实现的方法同时使用native关键字进行定义。
    在这里插入图片描述
    native指的是调用本机的原生系统函数。

Thread 类有个 registerNatives 本地方法,该方法主要的作用就是注册一些本地方法供 Thread 类使用,如 start0(),stop0() 等等,可以说,所有操作本地线程的本地方法都是由它注册的。这个方法放在一个 static 语句块中,当该类被加载到 JVM 中的时候,它就会被调用,进而注册相应的本地方法。而本地方法 registerNatives 是定义在 Thread.c 文件中的。Thread.c 是个很小的文件,它定义了各个操作系统平台都
要用到的关于线程的公用数据和操作,如下:
在这里插入图片描述
观察上边一小段代码,可以容易的看出 Java 线程调用 start->start0 的方法,实际上会调用到 JVM_StartThread 方法
在 jvm.cpp 中,有如下代码段:
在这里插入图片描述
这里JVM_ENTRY是一个宏,用来定义JVM_StartThread 函数,可以看到函数内创建了真正的平台相关的本地线程,其线程函数是 thread_entry,如下:
在这里插入图片描述
可以看到调用了vmSymbolHandles::run_method_name 方法,而run_method_name是在 vmSymbols.hpp 用宏定义的:
在这里插入图片描述

因此我们可以知道,Java线程创建的调用流程如下:
(未启动状态)start()->start0()->进行资源调度,系统分配(JVM)->run(Java方法)执行线程的具体操作任务

Runnable()接口实现多线程

观察Runnable接口:
在这里插入图片描述
范例:用Runable接口实现多线程

class MyThread implements Runnable{
    private String title;
    public MyThread(String title){
       this.title=title;
    }
    public void run(){
        for(int i=0;i<3;i++){
            System.out.println(this.title+" "+i);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread myThread1=new MyThread("线程1");
        MyThread myThread2=new MyThread("线程2");
        MyThread myThread3=new MyThread("线程3");
        //Thread类提供的构造方法:public Thread(Runnable target)
       new Thread(myThread1).start();
        new Thread(myThread2).start();
        new Thread(myThread3).start();

    }
}

在这里插入图片描述
范例:使用匿名内部类进行Runnable对象创建

public class Test {
    public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            for(int i=0;i<3;i++){
                System.out.println("hello");
            }
        }
    }).start();
    }
}

范例:使用Lamdba表达式进行Runnable对象创建

public class Test {
    public static void main(String[] args) {
        Runnable runnable=()->System.out.println("hello");
    new Thread(runnable).start();
    }
}
Thread与Runnable区别

先看下Thread类的定义

public  class Thread implements Runnable

1.Thread类与自定义线程类(实现了Runnable接口),是一个典型的代理设计模式。Thread类负责辅助真实业务操作(资源调度,创建线程并启动)
2. 自定义线程类负责真实业务的实现(run方法具体做啥事)
3. 使用Runnable接口实现的多线程程序类可以更好的描述共享的概念
范例:使用Thread实现数据共享(产生若干线程进行同一数据的处理操作)

class MyThread extends Thread{
    private Integer ticket=3;
    private String title;
    public MyThread(String title){
        this.title=title;
    }
    public void run(){
        for(int i=0;i<3;i++){
            System.out.println(this.title+"还剩下"+this.ticket+"---票");
            this.ticket--;
        }
    }
}
public class Test {
    public static void main(String[] args) {
      new MyThread("黄牛A").start();
      new MyThread("黄牛A").start();
      new MyThread("黄牛A").start();
    }
}

运行结果:启动三个线程实现卖票处理,结果变为了各自卖个自的票了
在这里插入图片描述
范例:使用Runnable实现共享

class MyThread implements Runnable{
    private Integer ticket=3;
    private String title;
    public MyThread(String title){
        this.title=title;
    }
    public void run(){
        for(int i=0;i<3;i++){
            System.out.println(this.title+"还剩下"+this.ticket+"---票");
            this.ticket--;
        }
    }
}
public class Test {
    public static void main(String[] args) {
     MyThread mt=new MyThread("黄牛");
     Thread thread1=new Thread(mt);
        Thread thread2=new Thread(mt);
        Thread thread3=new Thread(mt);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行结果:三个线程一起卖票
在这里插入图片描述

Callable实现多线程

从JDK1.5开始追加了新的开发包:java.util.concurrent。这个开发包主要是进行高并发编程使用的,包含很多在高并发操作中会使用的类。在这个包里定义有一个新的接口Callable
在这里插入图片描述

Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。
范例::使用Callable实现多线程

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread implements Callable<String> {
    private Integer ticket=3;
    public String call(){
        for(int i=0;i<3;i++){
            System.out.println("还剩下"+this.ticket+"---票");
            this.ticket--;
        }
        return "票买完啦~";
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        FutureTask<String> futureTask=new FutureTask<String>(myThread);
        Thread thread=new Thread(futureTask);
        Thread thread1=new Thread(futureTask);
        thread.start();
        thread1.start();
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

运行结果:票买完就不会再买了
在这里插入图片描述

Callable实现多线程(juc)-当线程有返回值的时候只能实现Callable实现多线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值