【多线程基础知识】

简介: 【多线程基础知识】

【多线程基础知识】

00.前言

此文章建议把 java的线程六种状态那篇文章看一下。

01.概念:

Java 中,线程作为最小调度单位,进程作为资源分配的最小单位。 在 windows 中进程是不活动的,只是作为线程的容器,一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行。多线程就是有多个线程,CPU可以根据一定的算法来调度和切换线程。

注意:多线程程序在运行过程中如果没有加锁 可以在线程的任意代码运行过程中切换到另一个线程

02.第一个案例:

代码

class A extends Thread
{
    public void run()//只能调用run方法 run方法是Thread类里的方法 需要重写
    {
        while(true)
        {
            System.out.println("AAAA");
        }    
    }
}
class B extends Thread
{
    public void run()//只能调用run方法 run方法是Thread类里的方法 需要重写
    {
        while(true)
        {
            System.out.println("CCCCcc");
        }    
    }
}

public class TestThread_1
{
    public static void main(String[] args)
    {
        A aa=new A();
        //aa.run(); //单线程
        aa.start();//多线程 开启一个线程 并自动调用run方法,一个线程只能调用一次
        B bb=new B();
        bb.start();
        while(true)
        {
            System.out.println("BBBBB");    
        }
            
        
    }
    
}

结果

AAAA
AAAA

BBBBB
BBBBB

CCCCcc
CCCCcc
CCCCcc
CCCCcc

可以看多线程是交替执行这些线程,且执行几次是不确定的,执行顺序也是不确定的。

03.创建多线程的两种基础方式:

01 实现Runnable接口

class A implements Runnable
{
    public void run()
    {
        while(true)
        {
            System.out.println("AAAA");
        }    
    }
}
class B
{
    
}
public class TestThread_2
{
    public static void main(String[] args)
    {
        A aa=new A();
        Thread t=new Thread(aa);
        t.start();
//Runnable是一个接口 接口里面只有run这一个方法,所有必须先实现这个接口,然后传参到Thread类里 实例化一个Thread的对象 
//只有这样才能调用 Thread类里的start方法
//Thread(Runnable ob)Thread类接收的参数类型是Runnable
        
        B bb=new B();
        //Thread t=new Thread(bb); //错误,因为Thread类接收的参数类型是Runnable    
    }
}

解释

这种方式实现Runnable接口并书写run方法,我们的线程实际上就是运行run方法里面的程序,之后我们的Thread类传一个实现了Runnable接口的对象 然后 创建一个Thread对象t,t.start()则是启动了一个线程,自此我们有两个线程 一个是主线程(main) 一个是我们刚刚创建的线程。

02 继承Thread类

代码

class A extends Thread
{
    public void run()
    {
        System.out.printf("%s在执行\n",Thread.currentThread().getName());
        
    }
}
public class TestThread_3
{
    public static void main(String[] args)
    {
        A aa1=new A();
        aa1.start();
        aa1.setName("李四");//更改Thread-0的线程名
        A aa2=new A();
        aa2.start();
        A aa3=new A();
        aa3.start();
        System.out.printf("%s在执行\n",Thread.currentThread().getName());
        //Thread.currentThread()方法返回当前执行对象,getName方法获取当前对象名字
    }
// 注:线程的执行顺序按照系统默认给的优先级算。创建n个线程就有n+1个线程执行,那个1代表main函数里的线程    
}

结果

李四在执行
Thread-2在执行
Thread-1在执行
main在执行

解释:我们可以看出我们这种创建线程的方法是通过继承Thread类并重写run方法,我们的线程就是run里的程序,此外我们还可以通过setName方法来给线程命名

补充:我们推荐第一种创建方法,理由是如果我们要几个功能不同的线程,那么我们的第二种写法 就需要很多继承Thread的类并重写run方法,但是如果我们使用第一种方法 则可以实现多个Runnable接口 Thread类只需要传入不同的Runnable接口的类的对象 就可以实现。

04.多线程优先级

class T1 implements Runnable{
    public void run()
    {
        for(int i=0;i<100;i++)
        {
            System.out.println("T1:"+i);    
        }    
    }    
}
class T2 implements Runnable{
    public void run()
    {
        for(int i=0;i<100;i++)
        {
            System.out.println("--------T2:"+i);    
        }    
    }    
}

public class TestPriority
{
    public static void main(String[] args)
    {
        Thread t1=new Thread(new T1());
        Thread t2=new Thread(new T2());
        t1.setPriority(Thread.NORM_PRIORITY+3);//设定优先级 默认为5
        t1.start();
        t2.start();
    }    
}

解释:

我们通过setPriority方法来设置优先级,注意:线优先级是指优先级越高,越有可能先执行,但只是建议先执行,具体什么时候执行由系统决定。

05.sleep线程暂停方法

class A implements Runnable
{
    public void run()
    {
        for(int i=0;i<10;i++)
        {
            try
            {
                Thread.sleep(1000);//暂停一秒 在暂停的这一秒去运行另一个线程 且后面随机运行线程    
                //且sleep抛出必须处理的异常 使用只能用try
                //并且run方法不能通过throws返回给上一层处理,因为父类Runnable接口中的run方法 其中并没有抛出异常
                //子类处理异常的范围应该小于等于父类
            }    
            catch(Exception e)
            {}
            System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
            System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
            System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
            System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
        }    
    }    
    
}
public class TestSleep
{
    public static void main(String[] args)
    {
        A aa=new A();
        Thread tt=new Thread(aa);
        tt.start();
        while(true)
        {
            System.out.println("哈哈");
        }
        
    }    
}

解释

sleep方法是调用此方法的线程陷入等待即不在争抢(锁我们之后会介绍),在等待时间过去后会唤醒此线程,然后会继续争抢锁

06.join方法

public class TestJoin
{
    public static void main(String args[])
    {
        MyRunner r = new MyRunner();
        Thread t =  new Thread(r);
        t.start();
        try
        {
            t.join();//暂停当前正在t.join()的线程 直到另一个线程执行完才继续执行
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        for(int i=0;i<50;i++)
        {
            System.out.println("主线程: "+i);
        }
    }    
    
}

class MyRunner implements Runnable
{
    public void run()
    {
        for(int i=0;i<50;i++)    
            System.out.println("子线程: "+i);
    }    
}

解释

此方法的主要目的是可能某个线程可以运行需要其他线程的完成,此时我们用join方法把调用此方法的线程变为等待状态,在其他线程完毕后在唤醒此线程。

07.yield 线程让步方法

public class TestYield
{
    public static void main(String[] args)
    {
        MyThread mt=new MyThread();
        Thread t1=new Thread(mt);
        Thread t2=new Thread(mt);
        t1.setName("线程A");
        t2.setName("线程B");
        t1.start();
        t2.start();
    }    
}

class MyThread implements Runnable
{
    public void run()
    {
        for(int i=1;i<=100;i++)
        {
            System.out.println(Thread.currentThread().getName()+": "+i);
            if(0==i%10)
            {
                Thread.yield();    //yield是线程让步,当满足i%10==0时 强制把当前线程转换为就绪状态 另一个线程转换为运行状态
            }    
        }    
    }    
    
}

结果

线程A: 1
线程A: 2
线程B: 1
线程B: 2
线程B: 3
线程B: 4
线程B: 5
线程B: 6
线程A: 3
线程B: 7
线程A: 4
线程B: 8
线程A: 5
线程B: 9
线程A: 6
线程B: 10
线程A: 7

我们可以看到当线程B 运行到10 后 之后我们就切换到了线程A,注意 注释里的就绪态 指的是java的六种线程状态中的可运行状态,运行状态在java的六种线程状态中没有写 指的是cpu正在运行的状态

目录
相关文章
|
Java API 调度
并发编程系列教程(01) - 多线程基础
并发编程系列教程(01) - 多线程基础
69 0
|
6月前
|
存储 安全 Java
10分钟巩固多线程基础
10分钟巩固多线程基础
|
6月前
|
Java API 调度
[Java并发基础]多进程编程
[Java并发基础]多进程编程
128 0
|
Java 程序员 调度
多线程(初阶)——多线程基础
多线程(初阶)——多线程基础
88 0
|
Java API 调度
并发编程之多线程基础
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。
并发编程之多线程基础
|
缓存 安全 Java
6. 多线程基础
对一个程序的运行状态, 以及在运行中所占用的资源(内存, CPU)的描述; 一个进程可以理解为一个程序; 但是反之, 一个程序就是一个进程, 这句话是错的。
92 0
6. 多线程基础
|
安全 Java 编译器
多线程基础(上)
多线程基础(上)
67 0
多线程基础(上)
|
Java 编译器 程序员
多线程基础(下)
多线程基础(下)
102 0
多线程基础(下)
|
SpringCloudAlibaba 安全 前端开发
JUC系列(一) 多线程基础复习
问:如何学习JUC? 答: 源码 + Java帮助文档 面试高频, juc 其实就是 Java.util 包下的线程分类的工具
JUC系列(一) 多线程基础复习
多线程编程之线程扫盲
Java有这么多的线程池, 但是底层原理只有一个。其他都是对其进行的封装。不用死背面试题, 核心知识点很少,一篇文章征服面试官。
134 0