多线程基础一:深入浅出认识多线程及常用方法

一、线程基础知识

1、什么是线程

官方一点的解释:进程是资源分配的最小单位,线程是CPU调度的最小单位。
即进程可以理解为一个正在运行的程序,而线程就是进程中去各个模块执行任务的线程。

2、线程的两种常见的开启方法

package thread;

public class Demo02 {
    public static void main(String[] args) {
        //通过继承Thread类开启线程
        Thread t1 = new Thread01();
        t1.start();
        System.out.println("********分隔线**********");
        //通过实现Runnable接口开启线程
        Thread02 thread02 = new Thread02();
        Thread t2 = new Thread(thread02);
        t2.start();
    }
}

class Thread01 extends Thread {
    @Override
    public void run() {
        System.out.println("通过继承Thread类实开启线程!");
    }
}

class Thread02 implements Runnable {
    @Override
    public void run() {
        System.out.println("通过实现Runnable接口开启线程!");
    }
}

>但是java真的可以开启线程吗?
我们可以点击看一下start()方法源码:

    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         * 如果是0,则表示该线程是新创建的
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
	
	//底层其实使用的是c++语言编写的启动方法。java是无法直接操作硬件的
    private native void start0();

在这里插入图片描述

3、多线程生命周期

在这里插入图片描述
简单点说,线程的生命周期有五个状态:新建->就绪->运行->阻塞->死亡

4、关于并行和并发

并行: CPU多核,多个线程可以一起执行,以线程池为例子。
并发: CPU单核,多个线程快速交替。

二、常用的多线程方法

//获取当前线程对象
Thread.currentThread()
//设置和获得优先级,优先级越高,不一定就是先运行,看cpu心情,只是相对概率大一些
setPriority()
getPriority()
//礼让线程,只是让大家重回起跑线上,至于下个线程先启用谁,看cpu心情
yield()
//判断线程是否存活
isAlive()
//合并线程
jion()
//等待线程
wait()
//唤醒一个线程和所有线程
notify()
notifyAll()
//线程睡眠
sleep()
//线程中断
interrupt()

用几个案例体会一下:

package thread;
//测试优先级
public class Demo03 {
    public static void main(String[] args) {
        //开启三个线程
        Thread t1 = new Thread(new ThreadTest1(),"A");
        Thread t2 = new Thread(new ThreadTest1(),"B");
        Thread t3 = new Thread(new ThreadTest1(),"C");

        //设置优先级
        t1.setPriority(1);
        t2.setPriority(2);
        t3.setPriority(3);

        //运行
        t1.start();
        t2.start();
        t3.start();
    }
}

class ThreadTest1 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"正在运行!");
    }
}

出现的结果:
B正在运行!
C正在运行!
A正在运行!
理想中的结果:
C正在运行!
B正在运行!
A正在运行!

再来一个龟兔赛跑小实验:

package thread;

public class Race {
    public static void main(String[] args) {
        Run r = new Run();
        new Thread(r,"兔子").start();
        new Thread(r,"乌龟").start();
    }
}


class Run implements Runnable {
    private static String WINNER;

    @Override
    public void run() {
        for (int i = 0; i <=15000 ; i++) {
            if(isGameOver(i)) {
                break;
            }
            //如果当前线程是兔子的话,它每次可以多跑一步,兔子的速度要快。
            if (Thread.currentThread().getName().equals("兔子")) {
                System.out.println(Thread.currentThread().getName()+"跑了"+i+++"步");
            }else {
                System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
            }
        }
    }

    public boolean isGameOver(int i) {
       if (WINNER!=null){
           return true;
        }else {
           if (i>=15000) {
               WINNER = Thread.currentThread().getName();
               System.out.println("winner is"+WINNER);
               return true;
           }
           return false;
       }
    }
}

经过测试
乌龟跑了8898步
乌龟跑了8899步
winner is兔子
在步数范围较大时,基本都是兔子赢了

但是我们知道龟兔赛跑中,兔子在中途睡了一觉。所以我们增加一个方法

package thread;

public class Race {
    public static void main(String[] args) {
        Run r = new Run();
        new Thread(r,"兔子").start();
        new Thread(r,"乌龟").start();

    }
}


class Run implements Runnable {
    private static String WINNER;

    @Override
    public void run() {
        for (int i = 0; i <=15000 ; i++) {
            if(isGameOver(i)) {
                break;
            }
            //如果当前线程是兔子的话,它每次可以多跑一步
            if (Thread.currentThread().getName().equals("兔子")) {
                System.out.println(Thread.currentThread().getName()+"跑了"+i+++"步");

                try {
                    //兔子睡了一个大懒觉
                    Thread.sleep(1000*5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else {
                System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
            }
        }
    }

    public boolean isGameOver(int i) {
       if (WINNER!=null){
           return true;
        }else {
           if (i>=15000) {
               WINNER = Thread.currentThread().getName();
               System.out.println("winner is"+WINNER);
               return true;
           }
           return false;
       }
    }
}

经过测试
乌龟跑了14998步
乌龟跑了14999步
winner is乌龟

在龟兔赛跑中,我们让兔子进行等待睡眠调用的是sleep方法,那么,wait()方法的作用时什么呢?
字面意思,就是线程进入等待,特点就是wait()方法会释放一把锁,同时线程进入阻塞状态
底层实现:


/**
*This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.  wait方法一般都是和notify和notifyAll配合使用。
*/
//先是调用了一个无参方法
public final void wait() throws InterruptedException {
        //里面调用了一个有参方法,设置参数为0
        wait(0);
    }
//有参方法,是用C语言编写,底层实现就看不到了。
// @param      timeout   the maximum time to wait in milliseconds.最大的等待时长
public final native void wait(long timeout) throws InterruptedException;

那么。notify和notifyAll有什么区别呢?

//两个都是C语言写的方法
//Wakes up a single thread that is waiting on this object's monitor. 
//唤醒一个单线程,线程是随机抽取的,看CPU心情
public final native void notify();
//Wakes up all threads that are waiting on this object's monitor.
//唤醒所有被监控的线程
public final native void notifyAll();
    

好了,多线程基本的概念和方法使用大体上就是如此。不知道您这边是否有所收获呢?

猜你喜欢

转载自blog.csdn.net/weixin_39085109/article/details/106724529