java入门篇 (25) 多线程(基础)

一、进程概述及多进程的意义

1.1 线程概念

进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。 每一个进程都有它自己的内存空间和系统资源。

1.2 多进程的意义

使多个程序可以同时运行,可以提高cpu的使用率。

1.3 线程概述

在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位。

1.4 多线程的意义

多线程的作用不是提高执行速度,而是为了提高应用程序的使用率。我们程序在运行的使用,都是在抢CPU的时间片(执行权),如果是多线程的程序,那么在抢到CPU的执行权的概率应该比较单线程程序抢到的概率要大.那么也就是说,CPU在多线程程序中执行的时间要比单线程多,所以就提高了程序的使用率.但是即使是多线程程序,那么他们中的哪个线程能抢占到CPU的资源呢,这个是不确定的,所以多线程具有随机性.

1.5 并行和并发的区别

  • 前者是逻辑上同时发生,指在某一个时间段内同时运行。
  • 后者是物理上同时发生,指在某一个时刻同时运行。

1.5 Java程序运行原理

Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。

1.6JVM的启动是多线程的吗

JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

1.7 多线程如何实现

  • C/C++去调用系统功能创建进程
  • java可以调用C/C++写好的程序来实现多线程程序

1.8 run和strat方法的区别

我们启动线程使用不是run方法,而应该是start方法.使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

二、Thread类常用方法

2.1 Run()方法

  • run方法中封装应该是必须被线程执行的代码.
  • run()方法里一般是比较耗时的代码

2.1 获取和设置线程名方法

注意:getName()和setName()同时使用才会发挥作用

  • public final String getName()
    获取线程名称

  • public final void setName(String name)
    设置线程名称

  • 通过构造方法也可以给线程起名字

  • public static Thread currentThread()
    获取当前执行的线程(获取主线程)

2.3继承Thread类

分析:创建了两个thread对象,相当于要执行两个任务,所以每一个线程都要执行完对应的一个任务。

方式一:

public class text {
    public static void main(String[] args) {
        thread thread1 = new thread();
        thread thread2 = new thread();
        thread1.setName("?");
        thread2.setName("?");
        thread1.start();
        thread2.start();
    }
}

public class thread extends  Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.print(this.getName() + i + " ");
        }
    }
}

结果:
?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 

方式二:


public class thread extends Thread {
    String name;

    public thread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.print(name + i + " ");
        }
    }
}

public class text {
    public static void main(String[] args) {
        thread thread1 = new thread("?");
        thread thread2 = new thread("?");
        thread1.start();
        thread2.start();
    }
}

2.3 实现Runnable接口

步骤:

  • 声明实现Runnable接口的类
  • 将上面的子类作为Thread参数,创建Thread的对象
public class text {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new myRunnable("?"));
        Thread thread2 = new Thread(new myRunnable("?"));
        thread1.start();
        thread2.start();
    }
}

public class myRunnable implements Runnable {
    String name;
    public myRunnable(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(name + i + " ");
        }
    }
}

2.4 实现Callable接口

public class text {
    public static void main(String[] args) {
        FutureTask task = new FutureTask(new myCallble());
        Thread th1 = new Thread(task);
        Thread th2 = new Thread(task);
        th1.setName("?");
        th2.setName("?");
        th2.start();
        th1.start();
    }
}

public class myCallble implements Callable {
    @Override
    public Object call() throws Exception {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + i + " ");
        }
        return null;
    }
}

2.5 run()方法和call方法的区别

  • run()方法没有返回值,call方法有返回值
  • run()方法只能通过try…catch方法来捕获异常,不能抛出异常,call()方法可以抛出异常。

2.6 线程调度模型

  • 分时调度模型
    所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
  • 抢占式调度模型
    优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。
  • Java使用的是抢占式调度模型。

2.7 设置和获取线程优先级

  • public final int getPriority()
    获取线程的优先级
  • public final void setPriority(int newPriority)
    设置线程的优先级

注意事项: 有的时候我们给线程设置了指定的优先级,但是该线程并不是按照优先级高的线程执行,那是为什么呢?
因为线程的优先级的大小仅仅表示这个线程被CPU执行的概率增大了.但是我们都知道多线程具有随机性,所以有的时候一两次的运行说明不了问题

  • 线程的优先级的范围是: 1 - 10
  • 如果优先级不在范围,则会抛出IllegalArgumentException异常

三、线程控制

3.1 线程控制之休眠线程

  • public static void sleep(long millis)
    线程休眠
import java.util.concurrent.Callable;
public class myCallble implements Callable {
    @Override
    public Object call() throws Exception {
        for (int i = 0; i < 5; i++) {
            Thread.currentThread().sleep(100);
            System.out.println(Thread.currentThread().getName() + i + " ");
        }
        return null;
    }
}

3.2 线程控制之加入线程

  • public final void join()

注意事项:

  • 等待该线程执行完毕了以后,其他线程才能再次执行
  • 在线程启动之后,在调用方法
public class text {
    public static void main(String[] args) throws InterruptedException {
       thread th1 = new thread();
       thread th2 = new thread();
       thread th3 = new thread();
       th1.setName("?");
       th2.setName("?");
       th3.setName("?");
       th1.start();
       th1.join();
       th2.start();
       th3.start();
    }
结果:
?0 
?1 
?2 
?3 
?4 

3.3 线程控制之礼让线程

  • public static void yield()
    暂停当前正在执行的线程对象,并执行其他线程。

注意事项:
这个礼让是要暂停当前正在执行的线程,这个暂停的时间是相当短的,如果在这个线程暂停完毕以后,其他的线程还没有抢占到CPU的执行权,那么这个时候这个线程应该再次和其他线程抢占CPU的执行权.

可能会出现线程交替执行

public class thread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            Thread.yield();
            System.out.println(Thread.currentThread().getName() + i + " ");
        }
    }
}

3.4 线程控制之守护线程

  • public final void setDaemon(boolean on)
    特点:
  • 将该线程标记为守护线程或用户线程。
  • 当正在运行的线程都是守护线程时,Java 虚拟机退出。
  • 该方法必须在启动线程前调用。
  • 被标记为守护线程的线程运行停止,其他线程也停止运行。不一定是立即停止。
  • 该方法必须在启动线程前调用。
public class text {
    public static void main(String[] args) throws InterruptedException {
       Thread th1 = new Thread(new thread());
       Thread th2 = new Thread(new thread());
       Thread th3 = new Thread(new thread());
       th1.setName("?");
       th1.setDaemon(true);
       th2.setName("?");
       th2.setDaemon(true);
       th3.setName("?");
       th1.start();
       th2.start();
       th3.start();
    }
}

3.5 线程控制之中断线程

  • public final void stop()

停止线程的运行

  • public void interrupt()

查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值