Java笔记--多线程

Java笔记–多线程

在讲线程之前有必要讨论一下进程的定义:进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。进程实体由程序段, 数据段 PCB(进程控制块)组成。线程又是什么?线程可以看做轻量级进程,线程是进程的执行单元,是进程调度的基本单位

还有一个概念就是并发性(concurrency)和并行性(parallel):并行是指在同一时刻,有多条指令在多个处理器上同时运行;并发指的是在同一时刻只能有一条指令执行,即每个指令以时间片为单位来执行
这里写图片描述

1,线程的创建与启动

Java使用Thread类代表线程,所有线程对象都是Thread类或其子类的实例

1.1,继承Thread类来创建并启动多线程

public class FirstThread extends Thread{

    private int i;

    @Override
    public void run() {
        for(i=0;i<100;i++) {
            //返回当前线程的名字
            System.out.println(getName()+" "+i);
        }
    }

    public static void main(String[] args) {


        for(int i=0;i<100;i++) {
            //获取当前线程
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20) {

                //创建并启动第一个线程
                new FirstThread().start();
                //创建并启动第二个线程
                new FirstThread().start();


                /*FirstThread st1 = new FirstThread();
                st1.start();
                FirstThread st2 = new FirstThread();
                st2.start();*/
            }
        }
    }   
}

这里写图片描述
继承Thread类,重写该类的run()方法,也就是这个线程需要完成的任务,线程对象的start()方法可以用来启动该线程
使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量

1.2,实现Runnable接口创建线程类

public class SecondThread implements Runnable{

    private int i;
    @Override
    public void run() {
        for(;i<100;i++) {

            //实现Runnable接口时,想获取当前线程只能用Thread.currentThread
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
    }

    public static void main(String[] args) {
        for(int i=0;i<100;i++) {
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20) {
                SecondThread  st = new SecondThread();

                new Thread(st,"新编程1").start();
                new Thread(st,"新编程2").start();

                /*Thread t1 = new Thread(st,"新编程1");
                t1.start();
                Thread t2 = new Thread(st,"新编程2");
                t2.start();*/

            }
        }
    }
}

这里写图片描述

实现Runnable接口,同样的在run()方法中编写需要线程实现的操作,采用线程对象的start()方法启动,
使用实现Runnable接口的方法来创建线程类时,多个线程之间可以共享线程类的实例变量

1.3,实现Callable接口通过FutureTask包装器来创建Thread线程

Callable接口提供了一个call()方法可以作为线程执行体,这个方法具有返回值,还可以声明抛出异常

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class ThirdThread {
    public static void main(String[] args) {
        //创建Callable对象
        ThirdThread rt = new ThirdThread();
        //先使用Lambda表达式创建Callable<Integer>对象
        //使用FutureTask来包装Callable对象
        FutureTask<Integer> task = new FutureTask<>((Callable<Integer>)()->{
            int i=0;
            for(;i<100;i++) {
                System.out.println(Thread.currentThread().getName()+"循环变量i的值:"+i);
            }
            return i;
        });
        for(int i=0;i<100;i++) {
            System.out.println(Thread.currentThread().getName()+" 的循环变量i的值:"+i);
            if(i==20) {
                //实质还是以Callable对象来创建并启动的
                new Thread(task,"有返回值的线程").start();

                /*Thread t = new Thread(task);
                t.start();*/
            }
        }
        try {
            System.out.println("子线程的返回值:"+task.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

这里写图片描述

1.4,Runnable,Callable接口与Thread类的对比

采用实现Runnable,Callable接口优缺点:
1,接口可以多继承,继承了Runnable接口还能继承其他接口
2,适合多个相同线程来处理同一份资源的情况,
3,缺点是,编程稍微复杂,访问当前线程必须使用Thread.currentThread()
采用继承Thread类优缺点:
1,编写简单,访问当前线程可直接用this
2,缺点是,不能再继承其他类
综上,建议采用实现Runnable接口的方法来创建和启动线程

1.5,synchronized关键字

synchronized关键字用于修饰方法和代码块,以实现同步,当多个线程在执行被synchronized修饰的代码,以排队的方式进行处理。当一个线程调用被修饰的代码时,先判断有没有被上锁,如果上锁就说明有其他线程在调用,必须等待其他线程结束调用后才能执行这段代码,synchronized可以在任意对象以及方法上加锁,加锁的这段代码被称为“互斥区”或者“临界区”
synchronized关键字加到static静态方法是给Class类上锁,而synchronized关键字加到非static静态方法上是给对象上锁

2,线程的生命周期

这里写图片描述

在线程的生命周期中,要经过新建(new),就绪(Runnable),运行(Running),阻塞(Blocked)和死亡(Dead)5种状态,CPU会在不同的线程之间来回切换,线程会不断的经历运行,阻塞

1,新建状态:使用new关键字创建了一个线程,如Thread t = new MyThread();

2,就绪状态:线程对象调用了start()方法后,线程进入就绪状态,就绪状态就是等待CPU的调度执行

3,运行状态:CPU调用就绪状态的线程,此时线程进入运行状态

4,阻塞状态:处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态

5,死亡状态:线程执行完毕或者异常退出,也可以用stop()方法来结束线程,但是容易造成死锁

这些都是java多线程编程最基础的东西,后面的等我看完《Java多线程编程核心技术》再来写

猜你喜欢

转载自blog.csdn.net/qq_37438740/article/details/81109226