首页 > 编程语言 >多线程详解——Java

多线程详解——Java

时间:2022-10-04 12:33:05浏览次数:65  
标签:Java Thread MyThread 详解 线程 new 多线程 public 守护

多线程详解——Java.Thread

1.1 多任务

​ 在计算中,多任务是一种多个任务(也称之为进程)共享处理资源(如CPU)的方法。在多任务操作系统上,例如Windows XP,您可以同时运行多个应用程序。多任务实质是指操作系统在每个计算任务间快速切换,以致于看上去不同的应用似乎在同时执行多项操作。当CPU时钟频率稳步提高时,不仅应用程序的运行速率可以更快,而且操作系统在应用间的切换速率也更快。这样就提供了更好的整体性能——一台计算机可以同时发生多项操作,每项应用可以更快速地运行。

1.2 程序,进程,线程

1.程序(program):是为完成特定任务、用某种语言编写的一组指令的集合。即指一 段静态的代码,静态对象。

2、进程(Process):是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。—生命周期

  进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

3、线程(Thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。

  1)若一个进程同一时间并行执行多个线程,就是支持多线程的

  2)线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小

  3)一个进程中的多个线程共享相同的内存单元/内存地址空间它们从同一堆中分配对象,可以 访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患

img

​ 一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc() 垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。

1.3 线程创建

创建一个新的执行线程有两种方法。

图片1

1.继承Thread类

一个是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。

(线程开启不一定立即执行,有CPU调度执行)

class MyThread extends Thread {
         public void run() {
              . . .
         }
     }

比如说我使用多线程从网上下载三张图片:

package com.dgut;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class MyThread extends Thread{
    String url;
    String name;
    public MyThread(String url,String name){
        this.url = url;
        this.name = name;
    }
    @Override
    public void run() {
        WebLoad webLoad = new WebLoad(url,name);
        System.out.println("下载了图片"+name);
    }
    public static void main(String[] args) {
        MyThread t1 = new MyThread("https://pics3.baidu.com/feed/aa64034f78f0f736bf2dffdd5eaebe10e9c4131a.jpeg?token=bd72d0c2a5381c455e8421f904868dd9","1.jpg");
        MyThread t2 = new MyThread("https://pics6.baidu.com/feed/b3b7d0a20cf431ad11f241b61fcda1a62fdd9825.jpeg?token=081d60e4180c5f45a9608e1b9fdc4738","2.jpg");
        MyThread t3 = new MyThread("https://pics2.baidu.com/feed/960a304e251f95caf4a39d7085ec7237650952a1.jpeg?token=82c61ff80d87cd1771d45e408e2c5654","3.jpg");
        t1.start();
        t2.start();
        t3.start();
    }
}
class WebLoad{
    public WebLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("成功下载图片 "+name);
        }
    }
}

image-20210904123652673image-20210904123707295

2.实现Runnable接口:

  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程体
  • 创建线程对象,调用start()方法启动线程
class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }
		
         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }
 
然后,以下代码将创建一个线程并启动它运行: 

     PrimeRun p = new PrimeRun(143);
     new Thread(p).start();
 

实现Runnable接口可以不用继承Thread类,避免了继承Thread后不能继承其他类的局限

故推荐实现Runnable接口

3.扩展:匿名对象的使用方法:

1 当对象对方法仅进行一次调用的时候,就可以简化成匿名对象。
如一个 对象需要进行调用方法2次,用匿名对象的

new Car().run()

new Car().run()

这是2个对象分别调用了run(),不是一个对象调用了多方法。

2 匿名对象可以作为实际参数进行传递。
public static void show(Car c)
{
//......
}

show(new Car());

1.4 线程不安全

​ 多个线程操作同一个资源的情况下,线程不安全,数据紊乱;

例子:

package com.dgut;

import static java.lang.Thread.*;

public class TextRunnable implements Runnable {

    private int ticket = 10;  //票数为10
    public void run() {
        while(true){
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(ticket<=0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"获得了第"+ticket--+"张票");
        }
    }

    public static void main(String[] args) {
        TextRunnable textRunnable = new TextRunnable();
        new Thread(textRunnable,"甲1").start();
        new Thread(textRunnable,"甲2").start();
        new Thread(textRunnable,"甲3").start();
    }
}

image-20210904134836131

​ 甲2和甲3两个顾客都抢到了第一张票;

1.5 实现Callable接口

  • 实现Callable接口
  • 重写call方法
  • 创建目标对象
  • 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool()
  • 提交执行: Future r1 = ser.submit(Thead thead);
  • 获取结果: boolean rs1 = r1.get();
  • 关闭服务: ser.shutdownNow();
package com.dgut;

import java.util.concurrent.*;

public class MyThread implements Callable<Boolean> {
    public Boolean call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"运行");
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService ser = Executors.newFixedThreadPool(3);

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        Future<Boolean> r1 = ser.submit(t1);
        Future<Boolean> r2 = ser.submit(t2);
        Future<Boolean> r3 = ser.submit(t3);
        boolean rs1 = r1.get();
        boolean rs2 = r2.get();
        boolean rs3 = r3.get();
        ser.shutdownNow();
    }
}

1.6 静态代理对象

1.7 Lamda表达式

  • 避免匿名内部类定义过多
  • 使得代码更加简洁
  • 去掉一堆没有意义的代码,只留下逻辑;

函数式接口

  • 任何接口,如果只包含一个抽象方法,那么它就是一个函数式接口。
public interface Runnable{
	public abstract void run();
}
  • 对于函数式接口,我们都可以用lambda表达式来创建该接口的对象;

    new Thread(()->{System.out.print("多线程学习")}).start;
    
  • lambda表达式只能有一行代码的情况下才能简化一行,如果有多行那么只能用代码块包裹;(前提是接口是函数性接口)

  • 多个参数也可以去掉类型,要去掉就都去掉,必须加上括号;

public class MyThread {
    public static void main(String[] args) {
       /* ILove love = new ILove(){
            @Override
            public void love() {
                System.out.println("love you");
            }
        };
        love.love();*/
        
        ILove iLove = null;
        iLove = ()-> System.out.println("love you too");
        iLove.love();
    }
}
interface ILove{
    void love();
}

1.8 线程礼让:

  • 礼让线程,让当前运行的线程暂停,但不阻塞;
  • 将线程从运行状态转为就绪状态;
  • 让CPU重新调度,礼让不一定成功!看CPU心情;
Thread.yield();

1.9 线程强制执行

自己阻塞,让其他线程运行;

Thread.join();

2.0 观察线程状态

image-20210906160145529

Thread.State state = thread.getState();
//
判断线程是否死亡状态
while(state != Thread.State.TERMINATED){
	...
}

2.1 线程优先级

 MyThread t1 = new MyThread();
 ti.setpriority(2);//优先级数为 1~10
 ti.start();
 

2.2 守护线程

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)

用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:

只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。

值得一提的是,守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。下面的方法就是用来设置守护线程的。

Thread daemonTread = new Thread();
 
  // 设定 daemonThread 为 守护线程,default false(非守护线程)
 daemonThread.setDaemon(true);
 
 // 验证当前线程是否为守护线程,返回 true 则为守护线程
 daemonThread.isDaemon();

2.3 死锁

2.4 生产者消费者问题

  • 信号灯法

标签:Java,Thread,MyThread,详解,线程,new,多线程,public,守护
From: https://www.cnblogs.com/Mr-Thorns/p/16753576.html

相关文章

  • 0579-5.15.1-Java 应用程序中修改Kerberos ticket_lifetime参数无效异常分析
    作者:辉少1文档编写目的在Kerberos环境中,我们的应用程序通过Java代码来提交任务需要先进行Kerberos凭证的初始化然后进行应用程序的提交,本文档主要讲述Java应用程序中读取krb......
  • 0578-5.15.1-Kerberos环境下Java应用程序认证超时异常分析
    作者:谢敏灵/辉少1文档编写目的在Kerberos环境中,我们的应用程序通过Java代码来提交任务需要先进行Kerberos凭证的初始化然后进行应用程序的提交,本文档主要讲述Java应用程序长......
  • 几个常见的javascript手写题,你能写出来几道
    实现new过程:要点:函数第一个参数是构造函数实例的__proto__指向构造函数的原型属性prototype函数剩余参数要挂载到一个实例对象上构造函数有返回值时,就返回这个返回......
  • OpenGL之多线程渲染
    随着Vulkan的引入,我们的图形技术的发展到达了一个新的顶点,但是呢,我们的老干爹OpenGL作为落日余晖,他在一些Vulkan才有的新功能上,也提供了一些支持。现在我们来讨论一下OpenG......
  • JAVA-DDD项目结构
    通过一套合理的代码结构、框架和约束,来降低DDD的实践门槛,提升代码质量、可测试性、安全性、健壮性。废话少说,直接上最终架构图:项目架构DDD的架构能够有效的解决传统......
  • Java并发编程 | 从进程、线程到并发问题实例解决
    计划写几篇文章讲述下Java并发编程,帮助一些初学者成体系的理解并发编程并实际使用,而不只是碎片化的了解一些Synchronized、ReentrantLock等技术点。在讲述的过程中,也想融入......
  • Java SE 宋红康 days04-高级篇-反射
    1.需要掌握的点:①理解Class类并获取Class实例;②创建运行时类的对象;③调用运行时类的指定结构;2.反射(Reflection)正常方式:引入需要的“包类”......
  • 构建Java高并发高性能分布式框架,高可维护性Java应用系统
    构建Java高并发高性能分布式框架,高可维护性Java应用系统微服务架构模式(MicroserviceArchitectPattern)。近两年在服务的疯狂增长与云计算技术的进步,让微服务架构受到重......
  • 桥接模式【Java设计模式】
    桥接模式【Java设计模式】​​前言​​​​推荐​​​​桥接模式​​​​介绍​​​​实现​​​​最后​​前言2022/9/2313:34路漫漫其修远兮,吾将上下而求索本文是根据袁......
  • Java10/04
    数组1.数组概述数组的定义:数组是相同类型数据的有序集合数组描述的是相同类型的若干个数控,按照一定的先后次序排列组合而成其中,每一个数据称为一个数组元素,每个数......