• 多线程基本概念


    1)线程包括哪些状态,分别是什么?

    1.新建状态(new)  :线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()

    2.就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行

    3.运行状态(Running):线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态

    4.阻塞状态(Blocked)阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
        (01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
        (02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
        (03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕

    5.死亡状态(dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    2)实现多线程的方式

    1.继承Thread类,重写run()方法

    Thread本质上也是实现了Runnable接口的一个实例,它代表了一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()方法

    代码实现:

    public class MyThread extends Thread {
        private int ticket = 10;
    
        public void run() {
            for (int i = 0; i < 20; i++) {
                if (this.ticket > 0) {
                    System.out.println(this.getName() + " 卖票:ticket" + this.ticket--);
                }
            }
        }
    
        public static void main(String[] args) {
            MyThread thread1 = new MyThread();
            MyThread thread2 = new MyThread();
            MyThread thread3 = new MyThread();
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }

    运行结果:

    Thread-1 卖票:ticket10
    Thread-1 卖票:ticket9
    Thread-1 卖票:ticket8
    Thread-1 卖票:ticket7
    Thread-1 卖票:ticket6
    Thread-1 卖票:ticket5
    Thread-1 卖票:ticket4
    Thread-1 卖票:ticket3
    Thread-1 卖票:ticket2
    Thread-1 卖票:ticket1
    Thread-0 卖票:ticket10
    Thread-0 卖票:ticket9
    Thread-0 卖票:ticket8
    Thread-0 卖票:ticket7
    Thread-2 卖票:ticket10
    Thread-0 卖票:ticket6
    Thread-2 卖票:ticket9
    Thread-2 卖票:ticket8
    Thread-2 卖票:ticket7
    Thread-2 卖票:ticket6
    Thread-2 卖票:ticket5
    Thread-2 卖票:ticket4
    Thread-2 卖票:ticket3
    Thread-2 卖票:ticket2
    Thread-2 卖票:ticket1
    Thread-0 卖票:ticket5
    Thread-0 卖票:ticket4
    Thread-0 卖票:ticket3
    Thread-0 卖票:ticket2
    Thread-0 卖票:ticket1

     

    2.实现Runnable接口,并实现run()方法

    以下是主要步骤:

    1)自定义类并实现Runnable接口,实现run()方法。

    2)创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象

    3)调用Thread的start()方法

    代码实现:

    public class MyThread implements Runnable {
        private int ticket = 10;
    
        public void run() {
            for (int i = 0; i < 20; i++) {
                if (this.ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + " 卖票:ticket" + this.ticket--);
                }
            }
        }
    
        public static void main(String[] args) {
            MyThread myThread=new MyThread();
            Thread thread1=new Thread(myThread);
            Thread thread2=new Thread(myThread);
            Thread thread3=new Thread(myThread);
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }

    运行结果:

    Thread-0 卖票:ticket9
    Thread-1 卖票:ticket10
    Thread-2 卖票:ticket8
    Thread-1 卖票:ticket6
    Thread-0 卖票:ticket7
    Thread-1 卖票:ticket4
    Thread-2 卖票:ticket5
    Thread-1 卖票:ticket2
    Thread-0 卖票:ticket3
    Thread-2 卖票:ticket1

    说明:运行结果表示一共卖出了10张票,说明这三个线程共享了Runnable接口

    3.实现Callable接口,重写call()方法(这种方法不常用)

    Callable接口实际是属于Executor框架中的功能类...

    3)run()方法和start()方法有什么区别

    start()方法:作用为启动一个线程,启动后该线程处于就绪状态,而非运行状态,也就意味着这个线程可以被JVM来调度执行。

    在调度过程中,JVM通过调用线程类的run()方法来完成实际的操作,当run()方法结束后,线程就会终止。

    run()方法:如果直接调用线程类的run()方法,会被当做一个普通函数调用,程序中仍然只有主线程这一个线程,并不会产生新的线程

    总的来说:start()方法能够异步地调用run()方法,但是直接调用run()方法却是同步的,无法达到多线程的目的

    代码示例:

    public class ThreadDemo extends Thread{
        @Override
        public void run() {
            System.out.println("ThreadDemo:begin");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ThreadDemo:end");
        }
    }
    public class StartAndRunTest {
        /*
        test1调用start()方法
         */
        public static void test1(){
            System.out.println("test1:begin");
            Thread t1=new ThreadDemo();
            t1.start();
            System.out.println("test1:end");
        }
    
        /*
        test2调用run()方法
         */
        public static void test2(){
            System.out.println("test2:begin");
            Thread t1=new ThreadDemo();
            t1.run();
            System.out.println("test2:end");
        }
    
        public static void main(String[] args) {
            test1();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println();
            test2();
        }
    }

    运行结果:

    从test1的运行结果来看,线程t1是在test1方法结束后才执行的,不需要等待t1,start()运行结束后(

     System.out.println("ThreadDemo:end")

    )就可以执行,说明在test1中调用start()是新开启了一个线程,main线程和t1线程是异步执行的

    从test2的执行结果来看,调用t1.run()是同步的调用,语句System.out.println("ThreadDemo:end")必须等t1.run()方法调用结束后

    才能 执行

     4)sleep()方法与wait()方法的区别

    1.原理不同。sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,它会使此线程暂停执行一段时间,而把执行机会让给

    其他线程,等到计时时间一到,此线程会自动“苏醒”。

    wait()方法是Object类的方法,用于线程间的通信,这个方法会使当前拥有该对象锁的进程等待,wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前的线程。

    2.对锁的处理机制不同。调用sleep()方法不会释放锁,而调用wait()方法会释放它所占用的锁,从而使线程所在对象中的其他synchronized数据可被别的线程使用。

    3.使用区域不同。由于wait()方法的特殊意义,因此它必须放在同步控制方法或者同步语句块中使用,而sleep()方法则可以放在任何地方使用

    还有就是sleep()方法必须捕获异常,而wait()方法不需要



  • 相关阅读:
    2017-2018-2 20179202《网络攻防技术》第一周作业
    《构建之法(第三版)》第四章
    《深入理解计算机系统(第三版)》第四章
    《文献管理与信息分析》第三章
    我们不一样
    linux centOS 7安装mysql 5.7.24
    centOS 8 使用dnf安装Docker
    centOS7服务器/dev/vda1空间100%,没有可用空间
    深刻理解 Docker 镜像大小
    使用linux docker环境打包Springboot jar包为docker镜像
  • 原文地址:https://www.cnblogs.com/wutongshu-master/p/10874090.html
Copyright © 2020-2023  润新知