JavaSE_multithreading

线程概述

  1. 进程:在windows操作系统中,每个独立的程序就称为是一个进程‘
  2. 线程:在一个程序运行时,就启动了一个进程,而在一个进程中还可以有多个执行单元同时运行,来同时完成一个或多个程序任务,这些执行单元可以看做程序执行的一条条线索,这就被称为线程。

线程的创建

多线程开发提供了非常优秀的技术,有三种方式可以实现多线程:第一种是继承Thread类,重写run()方法;第二种是实现Runnable接口,重写run()方法;第三种是实现Callable接口,重写call()方法,并使用Future来获取call()方法的返回结果。

  1. Thread类实现多线程
    主要步骤:
    创建一个Thread线程类的子类,同时重写Thread类的run()方法;
    创建该子类的实例化对象,并通过调用start()方法启动线程。
public class MyThread extends Thread {
    //创建子线程的有参构造方法

    public MyThread(String name) {
        super(name);
    }
    //重写Thread类的run()方法
    public void run(){
        int i=0;
        while (i++<5){
            System.out.println(Thread.currentThread().getName()+"的run()方法在运行");
        }
    }
}
class com{
    public static void main(String[] args) {
        //创建MyThread实例对象
        MyThread myThread1=new MyThread("thread1");
        //调用start()启动
        myThread1.start();
        //创建第二个
        MyThread myThread2=new MyThread("thread2");
        //再次调用
        myThread2.start();
    }
}
  1. Runnable接口实现多线程
    如歌使用Thread方式实现多线程,是有一定的局限性,因为java只支持单继承,莫个类已经继承的父类,就不能在被继承,就无法实现多线程。这个时候就可以实现Runnable接口实现多线程;步骤如下
    创建一个Runnable接口的实现类,同时重写接口中的run()方法;
    创建Runnable接口的实现类;
    使用Thread有参构造方法创建线程实例,并将Runnable接口的实现类的实例对象作为参数传入;
    调用线程实例的start()方法启动线程。
public class MyThread2 implements Runnable {
    //重写Runnable接口的run()方法
    @Override
    public void run() {
        int i = 0;
        while (i++ < 5) {
            System.out.println(Thread.currentThread().getName() + "的run()方法在运行");
        }
    }
}
class com1{
    public static void main(String[] args) {
        //创建Runnable接口的实现类的实例对象
        MyThread2 myThread2=new MyThread2();
        //使用Thread(Runnable target,String name)构造方法创建线程对象
        Thread thread1=new Thread(myThread2,"thread1");
        //调用并启动
        thread1.start();
        
        Thread thread2=new Thread(myThread2,"thread2");
        thread2.start();
    }
}
  1. Callable接口实现多线程
    前面两种方法均可以实现多线程,需要重写run()方法,但是由于该方法没的返回值,因此无法从多线程中获取返回结果,为了解决这个问题,我们可以使用Callable接口,具体步骤如下
    创建一个Callable接口的实现类,同时重写Callable接口的call()方法;
    创建Callable接口的实现类对象;
    通过FutureTask线程结果处理类的有参构造方法来封装Callable接口的实现类;
    使用参数为FutureTask类对象的Thread有参构造方法创建Thread线程实例;
    调用线程实例的start()方法启动线程。
class MyThread3 implements Callable<Object> {
    //重写
    @Override
    public Object call() throws Exception {
        int i = 0;
        while (i++ < 5) {
            System.out.println(Thread.currentThread().getName() + "的run()方法在运行");
        }
        return i;
    }
}
class com2{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建Callable接口的实现类对象
        MyThread3 myThread3=new MyThread3();
        //使用FutureTask封装Callable接口
        FutureTask<Object> ft1=new FutureTask<>(myThread3);
        //使用Thread(Runnable target,String name )构造方法创建线程对象
        Thread thread1=new Thread(ft1,"thread1");
        //启动
        thread1.start();

        FutureTask<Object> ft2=new FutureTask<>(myThread3);
        Thread thread2=new Thread(ft2,"thread2");
        thread2.start();
        
        //可以获取返回值
        System.out.println("thread1返回的结果"+ft1.get());
        System.out.println("thread2返回的结果"+ft2.get());
    }
}

线程的生命周期及状态转换

Java官方API将线程的整个生命周期分为6个状态,分别为NEW(新建状态)、RUNNABLE(可运行状态)、BLOCKED(阻塞状态)、WAITING(等待状态)、TIMED_WAITING(定时等待状态)、TERMINATED(终止状态)。

  1. NEW(新建状态) 创建一个线程后,该线程对象就处于新建状态,此时它不能运行,和其他Java对象一样,仅仅由JVM为其分配了内存,没有表现出任何线程的动态特征。
  2. RUNNABLE(可运行状态) 新创建的线程对象调用了start()方法,此时就是可运行状态了。在RUNNABLE状态内部又可细分为两种状态:READY(就绪状态)和RUUABLE(运行状态),并且线程可以在这个两个状态之间相互转换。
    就绪状态:线程对象调用start()方法之后,等待JVM的调度,此时线程并没有运行;
    运行状态:线程对象获得JVM调度,如果存在多个CPU,那么允许多个线程并行运行。
  3. BLOCKED(阻塞状态) 处于运行状态的线程可能会因为某些原因失去CPU的执行权,暂时停止运行进入阻塞状态。
  4. WAITING(等待状态)
    当运行状态的线程调度了无时间参数限制的方法后,如wait()、join()等方法,就会将当前运行中的状态转换为等待状态。
    处于等待状态的线程,必须等待其他线程调用notify()和notifyAll方法唤醒当前等待中的线程;调用join()方法而处于等待状态中的线程,必须等待其他加入的线程终止。
  5. TIMED_WAITING(定时等待状态) 当调用有时间参数限制的方法,如:sleep(long millis)、wait(long
    timeout)、join(long millis),将会计入该状态。
  6. TERMINATED(终止状态)
    线程的run()方法,call()方法正常执行完毕或者线程抛出一个未捕获的异常(Exception)、错误(error),线程就进入终止状态。

线程的调度

在计算机中,线程的调度有两种模型,分别是分时调度模型和抢占式调度模型。

  1. 线程的优先级
    线程的优先级用1~10之间的整数来表示,数字越大优先级越高。除了可以直接使用数字表示线程优先级,还可以使用Thread类中提供的三个静态常量表示线程优先级。可以通过Thread类的setPriority(int
    newPriority)方法对其设置优先级。
  2. 线程休眠 调用Thread的静态方法sleep(long millis)将可以进行线程休眠。
  3. 线程让步 可以通过调用yield()方法来实现。
  4. 线程插队 通过调用join()方法来实现。

多线程同步

同步代码块
使用关键字来修饰的代码块中,这段代码块被称为同步代码块,格式如下:
synchronized(lock){
//操作共享资源代码块
。。。。。
}
同步方法
使用synchronized关键字来修饰方法,语法格式如下:
[修饰符] synchronized 返回值类型 方法名([参数1,。。。]){}
同步锁
synchronized同步代码块和同步方法使用一种封闭式的锁机制,使用起来简单,并能够解决线程同步出现线程安全的问题;但无法中断一个正在等候获取锁的线程,也无法通过轮询得到锁,使用同步锁将能够解决这个问题。使用方法如下:
private final Lock lock=new ReentrantLock();//定义一个Lock锁对象
lock.lock();//对代码块进行加锁
代码块
finally{
lock.unlock();//执行完代码过后释放锁
}
死锁问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值