java_认识多线程

了解进程与线程的区别

进程:
是一个运行中的程序的实例
进程的两个特点:
(1)是一个实体,都有自己独立的地址空间,分文本区域,数据区域和堆栈,文本区域用来存储编写的程序的代码,数据区域用来存储用来运行时所需要的数据(动态分配内存),堆栈用来存储运行时涉及到的指令和本地变量
(2)是一个(运行中的程序),程序本身是没有生命的一个实体,只有当处理器赋予它生命时,它才能称之为一个活动实体,即进程,进程是操作系统级别的基本单元

通俗点说,进程就是操作系统运行的一个任务,一个应用程序运行时就对应一个进程

线程:
进程中所包含的一个或多个 执行单元称为线程(thread),一个线程就是进程中的一个 顺序执行流
进程拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问,即同一个进程中的多个线程共享一块内存空间和一组系统资源
线程只能归属于一个进程并且只能访问该进程所拥有的资源
线程本身也有一个供程序执行的堆栈,在线程切换时,负荷小,线程也被称之为轻负荷进程
    进程是程序的一次动态执行过程,它经历了从代码加载,执行到执行完毕的一个完整过程,这个过程是进程本身从产生、发展到最终死亡的过程。
    多线程是实现并发机制的一种有效手段。进程和线程一样,是实现并发的一个基本单位。
并发原理
多个线程”同时运行”只是我们感官上的一种表现,其实,线程是并发运行的.
操作系统将时间划分成很多时间片段,尽可能地均匀分配给每一个线程,获取时间片段的线程被CPU运行,二其他线程处于等待状态,所以微观上是走走停停,断断续续的,宏观上同时运行的现象叫并发
但绝不是真正的”同时发生”

掌握java线程的三种实现方式及其区别

在java中如果想实现多线程,可以采用以下三种方式:

  • 继承Thread类;
  • 实现Runnable接口;
  • 继承Callable< E >类;

继承Thread类

Thread类是在java.lang包中定义的,一个类只要继承了Thread类,此类就被称为多线程操作类。在Thread子类中,必须重写Thread类中的run()方法,该方法为线程的主体。最后创建线程对象,用start()方法开启任务。
注意:不是调用run()方法

定义语法:

class 类名 extends Thread {   
    属性...;           
    构造器...;
    方法...;
    public void run(){
        线程主体逻辑;
    }
}
/**
 * 方法1:
 * 通过继承Thread,完成线程的定义
 */
public class MyTask extends Thread{
    private String str;             //添加属性

    public MyTask(String name) {    //添加构造器
        this.str = name;
    }
    /*添加get()/set()方法*/
    public String getStr() {
        return str;
    }
    public void setStr(String str) {
        this.str = str;
    }

    /*重写run()*/
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println(this.getStr()+":"+i);
        }
    }
    public static void main(String[] args) {
        /*创建线程对象,启动任务*/
        Thread t1 = new MyTask("A");
        Thread t2 = new MyTask("B");
        t1.start();
        t2.start();
        System.out.println("main方法over");
    }
}

实现Runnable接口

在java中也可以通过实现Runnable接口的方式实现多线程,Runnable接口只定义了一个抽象方法;
public void run();
将Runnable的实现类对象传给Thread对象,再由Thread对象调用start()方法开启任务
注意:不可以直接使用Runnable的实现类对象直接调用start()方法,该实现类对象相当于Thread对象执行的任务对象

定义语法:

class 类名 implements Runnable{
    属性...;
    方法...;
    public void run(){
        线程主体逻辑;
    }
}
/**
 * 方法二:
 * 实现接口,完成任务的定义
 */
public class MyTask1 implements Runnable{
    int num = (int)(Math.random()*100+1);
    /*重写run(),定义任务体*/
    public void run() {
        for(int i=0;i<500;i++){
            System.out.println(num);
        }
    }
    public static void main(String[] args) {
        /*创建线程对象,启动任务*/
        Runnable r1 = new MyTask1();
        Runnable r2 = new MyTask1();
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();
        System.out.println("main方法结束");
    }
}

继承Callable< E >类

使用Callable< E >创建子类对象,然后重写call()方法(相当于run()方法),再将Callable< E >传给FutureTask< E >对象,再将FutureTask< E >对象传给Thread对象,调用start()方法,启动线程

定义语法:

class 类名 extends Callable<E> {  
    属性...;           
    构造器...;
    方法...;
    public E call(){
        线程主体逻辑;
    }
}
public class ThreadCallableDemo {
    public static void main(String[] args) {
        /*直接以匿名内部类的形式创建FutureTask对象*/
        FutureTask<String> task = 
                new FutureTask<String>(
                        new Callable<String>(){
                    /*实现call()方法*/
                    public String call(){
                        int num = 0;
                        for(int i=0;i<100;i++){
                            if(i%2!=0){
                                num+=i;
                                System.out.println(num);
                            }
                        }
                        return num+"";
                    }
                });
        /*创建线程对象,启动任务*/
        Thread t1 = new Thread(task);
        t1.start();
    }
}

三种创建线程实现方式的区别

前两种方式比较:
(1)将线程对象和任务对象分开,降低了耦合度,便于维护
(2)避免了java中单继承的限制
(3)适合相同的任务代码块处理同一个资源
第三种方式:call方法带有返回值

扫描二维码关注公众号,回复: 2994590 查看本文章

了解线程的操作状态

线程状态转换图

线程的状态图解析:

(1)新建状态,即新建一个线程对象,设置好需要执行的任务
(2)就绪状态:调用线程的start方法,进入准备状态,等待CPU分配时间片段
(3)运行状态:CPU将时间片段给了线程后,线程开始执行任务
(4)阻塞状态:正在运行的线程由于某种原因放弃CPU的使用权,即此线程放弃时间片段,进入阻塞状态

阻塞状态分为三种:
    等待阻塞:运行中的线程调用wait方法,jvm将此线程放入等待池中
    同步阻塞:运行中的线程想要获取同步的锁对象时,若锁对象被其他线程占用,则jvm将此线程放入锁池中
    其他阻塞:当线程执行到阻塞方法或Thread.sleep()或其他线程的加入时,此线程放弃时间片段,进入阻塞状态
(5)结束状态:当线程执行完任务后,表示结束

猜你喜欢

转载自blog.csdn.net/yc_hen/article/details/82261247