第四章 多线程

第四章 多线程线程 A 正在使用 sleep 暂停着 Thread sleep 如果要取消它的等待状态 可以在正在执行的线程里 比如这里是 B 调用 a interrupt a 是线程 A 对应到的 T

大家好,欢迎来到IT知识分享网。

第四章 多线程

进程:应用程序的执行实例,有独立的内存空间和系统资源

线程:cpu调度和分派的基本单位,进程中执行运算的最小单位,可完成一个独立的顺序控制流程

1.多线程

什么是多线程:

如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”

多个线程交替占用CPU资源,而非真正的并行执行

多线程好处:

充分利用CPU的资源、简化编程模型、带来良好的用户体验

2.主线程

Thread类Java提供了java.lang.Thread类支持多线程编程

主线程:

  • main()方法即为主线程入口
  • 产生其他子线程的线程
  • 必须最后完成执行,因为它执行各种关闭动作
public static void main(String args[]) { 
    Thread t= Thread.currentThread(); System.out.println("当前线程是: "+t.getName()); t.setName("MyJavaThread"); System.out.println("当前线程名是: "+t.getName()); } 

3.线程的创建和启动

创建线程的三种方式:

  1. 继承java.lang.Thread类
    • 定义MyThread类继承Thread类
    • 重写run()方法,编写线程执行体
    • 创建线程对象,调用start()方法启动线程
    //继承Thread类 public class MyThread extends Thread{ 
          //重写run()方法,编写线程执行体 @Override public void run() { 
          for (int i = 1;i < 100; i++){ 
          System.out.println(Thread.currentThread().getName()+":"+i); } super.run(); } public static void main(String[] args) { 
          //创建线程对象 MyThread thread = new MyThread(); //调用start()方法启动线程 thread.start(); } } 
    • 多个线程交替执行,不是真正的“并行”
    • 线程每次执行时长由分配的CPU时间片长度决定
    MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.start(); t2.start(); //运行结果: Thread-0:1 Thread-0:2 Thread-1:1 Thread-1:2 Thread-1:3 Thread-1:4 Thread-1:5 Thread-0:3 Thread-0:4 

    直接调用run()方法和调用start()方法:

    调用run()方法:

    主线程执行run(),只有主线程一条执行路径

    调用start()方法:

    子线程执行run()方法,多条执行路径,主线程和子线程并行交替执行

  2. 实现java.lang.Runnable接口
    • 定义MyRunnable类实现Runnable接口
    • 实现run()方法,编写线程执行体
    • 创建线程对象,调用start()方法启动线程
    //实现Runnable接口 public class MyRunnable implements Runnable{ 
          //实现run()方法 @Override public void run() { 
          for(int i=1;i<100;i++) { 
          System.out.println(Thread.currentThread().getName() + ":" + i); } } public static void main(String[] args) { 
          //创建线程对象 MyRunnable myRunnable = new MyRunnable(); Thread myThread = new Thread(myRunnable); //启动线程 myThread.start(); } } 

    比较两种创建线程的方式:

    • 继承Thread类
      • 编写简单,可直接操作线程
      • 适用于单继承
    • 实现Runnable接口
      • 避免单继承局限性
      • 便于共享资源
  3. 实现Callable<数据类型>接口
    • 定义MyCallable类实现Callable<数据类型>接口
    • 重写call方法(Callable有返回值),编写线程执行体
    import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class MyCallable implements Callable<String> { 
          @Override public String call() throws Exception { 
          for(int i=1;i<=10;i++) { 
          System.out.println(Thread.currentThread().getName() + ":" + i); } return "MyCallable线程"; } public static void main(String[] args) { 
          MyCallable myCallable = new MyCallable(); FutureTask<String> futureTask1 = new FutureTask<>(myCallable); FutureTask<String> futureTask2 = new FutureTask<>(myCallable); Thread thread1 = new Thread(futureTask1); thread1.start(); Thread thread2 = new Thread(futureTask2); thread2.start(); //接收返回值 try { 
          System.out.println(futureTask1.get()); }catch (Exception e){ 
          e.printStackTrace(); } } } 

使用线程的步骤:

定义线程、创建线程对象、启动线程、终止线程

4.线程的状态

创建状态、就绪状态、阻塞状态、运行状态、死亡状态

在这里插入图片描述

5.线程调度

线程调度指按照特定机制为多个线程分配CPU的使用权

方法 说明
void setPriority(int newPriority) 更改线程的优先级
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
void join() 等待该线程终止
static void yield() 暂停当前正在执行的线程对象,并执行其他线程
void interrupt() 中断线程
boolean isAlive() 测试线程是否处于活动状态

1.线程优先级

线程优先级是一个整数,范围在1(Thread.MIN_PRIORITY)到10(Thread.MAX_PRIORITY)之间。

默认优先级为5(Thread.NORM_PRIORITY),优先级高的线程获得CPU资源的概率较大

//setPriority(int newPriority) Thread t1 = new Thread(new MyThread(),"线程A"); Thread t2 = new Thread(new MyThread(),"线程B"); //线程A最高优先级 t1.setPriority(Thread.MAX_PRIORITY); t1.start(); //线程B最低优先级 t2.setPriority(Thread.MIN_PRIORITY); t2.start(); 

2.线程休眠

让线程暂时睡眠指定时长,线程进入阻塞状态,睡眠时间过后线程会再进入可运行状态

//static void sleep(long millis) millis为休眠时长,以毫秒为单位 for (int i = 0; i < 10; i++) { 
    System.out.println(i + 1 + "秒"); try { 
    //调用sleep()方法需处理InterruptedException异常 Thread.sleep(1000); } catch (InterruptedException e) { 
    e.printStackTrace(); } } 
//多线程: //定制日期格式 SimpleDateFormat forMater = new SimpleDateFormat("yyyy- MM-dd HH:mm:ss"); Thread t1 = new Thread(new MyThread(),"线程A"); System.out.println("线程A is running."); System.out.println("当前时间是:"+forMater.format(new Date())); try { 
    //调用sleep()方法需处理InterruptedException异常 t1.sleep(2000); } catch (InterruptedException e) { 
    e.printStackTrace(); } System.out.println("线程A is finished."); System.out.println("当前时间是:"+forMater.format(new Date())); Thread t2 = new Thread(new MyThread(),"线程B"); System.out.println("线程B is running."); System.out.println("当前时间是:"+forMater.format(new Date())); try { 
    //调用sleep()方法需处理InterruptedException异常 t2.sleep(5000); } catch (InterruptedException e) { 
    e.printStackTrace(); } System.out.println("线程B is finished."); System.out.println("当前时间是:"+forMater.format(new Date())); } 

3.线程的强制运行

强制执行当前线程,join写在哪个线程,就阻塞谁

public final void join() public final void join(long mills)//millis:以毫秒为单位的等待时长 public final void join(long mills,int nanos)//nanos:要等待的附加纳秒时长 需处理InterruptedException异常 
Thread temp = new Thread(new MyThread()); temp.start(); for(int i=0;i<20;i++){ 
    if(i==5){ 
    try { 
    temp.join(); } catch (InterruptedException e) { 
    e.printStackTrace(); }} System.out.println(Thread.currentThread().getName()+"运行:"+i); } 

4.线程的礼让

暂停当前线程,允许其他具有相同优先级的线程获得运行机会

该线程处于就绪状态,不转为阻塞状态

只是提供一种可能,但是不能保证一定会实现礼让

public void run() { 
    for(int i=0;i<5;i++){ 
    System.out.println(Thread.currentThread(). getName()+"正在运行:"+i); if(i==2){ 
    System.out.print("线程礼让:"); Thread.yield(); } } } public static void main(String[] args) { 
    Yield yield = new Yield(); Thread t1 = new Thread(yield,"线程A"); t1.setPriority(3); Thread t2 = new Thread(yield,"线程B"); t2.setPriority(3); t2.start(); t1.start(); } //运行结果: 线程B正在运行:0 线程A正在运行:0 线程B正在运行:1 线程B正在运行:2 线程礼让:线程A正在运行:1 线程A正在运行:2 线程礼让:线程B正在运行:3 线程B正在运行:4 线程A正在运行:3 线程A正在运行:4 

5.线程中断

调用interrupt()方法,立刻改变的是中断状态,但如果不是在阻塞态,就不会抛出异常;

如果在进入阻塞态后,中断状态为已中断,就会立刻抛出异常

public class test1 { 
    public static void main(String[] args) { 
    Thread thread = new Thread(){ 
    public void run() { 
    System.out.println("线程启动了"); while (!isInterrupted()) { 
    System.out.println(isInterrupted());//调用 interrupt 之后为true } System.out.println("线程结束了"); } } thread.start(); try { 
    Thread.sleep(1000); } catch (InterruptedException e) { 
    e.printStackTrace(); } thread.interrupt();//作用是:在线程阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态 } } 

1.sleep() & interrupt()

线程A正在使用sleep()暂停着: Thread.sleep(),如果要取消它的等待状态,可以在正在执行的线程里(比如这里是B)调用a.interrupt()[a是线程A对应到的Thread实例],令线程A放弃睡眠操作。即,在线程B中执行a.interrupt(),处于阻塞中的线程a将放弃睡眠操作。

当在sleep中时线程被调用interrupt()时,就马上会放弃暂停的状态并抛出InterruptedException。抛出异常的,是A线程。

2.wait() & interrupt()

线程A调用了wait()进入了等待状态,也可以用interrupt()取消。不过这时候要注意锁定的问题。线程在进入等待区,会把锁定解除,当对等待中的线程调用interrupt()时,会先重新获取锁定,再抛出异常。在获取锁定之前,是无法抛出异常的。

3.join() & interrupt()

当线程以join()等待其他线程结束时,当它被调用interrupt(),它与sleep()时一样,会马上跳到catch块里.。

6.多线程共享数据引发的问题

多个线程操作同一共享资源时,将引发数据不安全问题

同步方法: 解决并发问题

使用synchronized修饰的方法控制对类成员变量的访问

访问修饰符 synchronized 返回类型 方法名(参数列表){……}

synchronized 访问修饰符 返回类型 方法名(参数列表){……}

public synchronized void sale() { 
    if (count <= 0) { 
    flag = true; return; } 

同步代码块:

使用synchronized关键字修饰的代码块

synchronized(syncObject){ 
    //需要同步的代码 } syncObject为需同步的对象,通常为this 效果与同步方法相同 

多个并发线程访问同一资源的同步代码块时:

  • 同一时刻只能有一个线程进入synchronized(this)同步代码块
  • 当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
  • 当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码

7.线程安全的类型

方法是否同步 效率比较 适合场景
线程安全 多线程并发共享资源
非线程安全 单线程

查看ArrayList类的add()方法定义:

public boolean add(E e) { 
    ensureCapacityInternal(size + 1); //集合扩容,确保能新增数据 elementData[size++] = e; //在新增位置存放数据 return true; } 

ArrayList类的add()方法为非同步方法

当多个线程向同一个ArrayList对象添加数据时,可能出现数据不一致问题

ArrayList为非线程安全的类型

常见类型对比:

Hashtable && HashMap:

Hashtable:

继承关系:实现了Map接口,Hashtable继承Dictionary类

线程安全,效率较低

键和值都不允许为null

HashMap:

继承关系:实现了Map接口,继承AbstractMap类

非线程安全,效率较高

键和值都允许为null

StringBuffer && StringBuilder: 前者线程安全,后者非线程安全

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/126886.html

(0)
上一篇 2025-09-15 14:00
下一篇 2025-09-15 14:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信