多线程

进程:正在运行的程序,是系统进行资源分配和调用对的独立单位,每一个进程都有它的内存空间和系统资源。可以理解为,一个正在运行的程序。
线程:是进程中的单个顺序控制流,是一条执行路径,一个进程如果只有一条执行路径,则称为单线程程序;一个进程如果有多条执行路径,则称为多线程程序。

如何创建一个线程对象?
  • 1、自定义线程类继承Thread类,重写run方法
  • 2、自定义线程类实现Runable接口,实现run方法
如何启动一个线程?

​ 调用start()方法启动

Thread无参构造方法

thread() 分配一个新的 Thread对象

class MyThread1 extends Thread{
    MyThread1() {
    }

    MyThread1(String name){
        super(name);
    }

    @Override
    public void run() {
        //将来线程启动后需要执行的逻辑
        super.run();
    }
}

注意:

  • 1、启动一个线程的时候,若直接调用run方法,仅仅是普通的对象调用方法,按照自上而下的顺序执行,底层不会额外的创建一个线程再执行
  • 2、从执行结果上来看,java线程之间是抢占式执行的,谁先抢到cpu执行权谁就先执行
  • 3、每次运行的结果顺序不可预测,是完全随机的
  • 4、每个线程都有优先权,具有较高优先级的线程优先于优先级别低的线程执行

Thread类中的成员方法:

  • 1、public final String getName() 获取线程对象的名字
  • 2、设置线程对象名字的方式:
    • a.通过父类的有参构造方法,在创建线程对象的时候设置名字
    • b.线程对象调用setName(String name)方法,给线程对象设置名字
  • 3、获取进程的等级
    getPriority() 默认优先级是5
  • 4、设置进程优先级,setPriority(int i),在启动之前设置 [1,10]
    注意不是优先级高的一定先执行,只是可能性变高了。
public class ThreadDemo1 {
    public static void main(String[] args) {
        //创建一个自己的线程对象
        MyThread1 m1 = new MyThread1();
        m1.setName("🐱");
//        MyThread1 m1 = new MyThread1("🐱");
        m1.setPriority(10);
        System.out.println("m1:"+m1.getPriority());
    }
}

接下来让我们来尝试启动多线程,在run()方法中定义线程启动后的逻辑

@Override
    public void run() {
        for (int i = 1; i <= 10;i++){
            System.out.println(this.getName() + " - Hello world " + i);
        }
    }

启动多个线程,

public class TreadDemo2 {
    public static void main(String[] args) {
        MyThread2 m1 = new MyThread2();
        m1.setName("🐱");
        m1.setPriority(10);
        System.out.println(m1.getName()+"的优先级为:"+ m1.getPriority());

        MyThread2 m2 = new MyThread2();
        m2.setName("🐜");
        m2.setPriority(1);
        System.out.println(m2.getName()+"的优先级为:"+m2.getPriority());

        System.out.println("=======================");
        m1.start();  //m1.run();
        m2.start();  //m2.run();
    }
}

了解了线程的调度后,接下来我们可以以下使用方法进行线程控制

1、休眠线程

public static void sleep(long millis)

​ 当线程处于休眠状态的时候,该线程就没有cpu执行权了,若这时还有其他的线程,会被抢走cpu执行权。

以下是示例:

class SleepThread extends Thread{
    @Override
    public void run() {
        System.out.println(getName()+"睡着了。。。。");
        try {
            //这里使用try...catch..是因为sleep方法本身就抛出了一个异常,编译时期异常
            Thread.sleep(1000);
            //在哪个方法中调用,就是调用该方法的线程对象进行休眠
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(getName()+"睡醒了。。。。");
    }
}
public class ThreadSleepDemo1 {
    public static void main(String[] args) {
        SleepThread s1 = new SleepThread();
        s1.setName("🐱");
        s1.start();
    }
}

2、线程加入

public final void join()

​ 当线程调用join()方法后,如果存在其他线程,则在该线程执行结束后,其他线程之间会进行抢占式执行。

class JoinThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++){
            System.out.println(getName()+" - "+i);
        }
    }
}
public class ThreadJoinDemo1 {
    public static void main(String[] args) {
        JoinThread j1 = new JoinThread();
        JoinThread j2 = new JoinThread();
        JoinThread j3 = new JoinThread();
        j1.setName("🐱");
        j2.setName("🐕");
        j3.setName("🐖");

        j1.start();
        try {
            j1.join();// 其他线程等待该线程执行结束,其他线程之间会进行抢占式执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        j2.start();
        j3.start();
    }
}

3、线程礼让

public static void yield()

​ yield()只是为了运行结果看起来均匀一些

class YieldThread extends Thread{
    @Override
    public void run() {
        for(int i = 1; i <= 10 ;i++){
            System.out.println(getName()+" - "+i);
        }
    }
}
public class ThreadYieldDemo1 {
    public static void main(String[] args) {
        YieldThread y1 = new YieldThread();
        YieldThread y2 = new YieldThread();
        y1.setName("🐱");
        y2.setName("🐕");

        y1.start();
        y2.start();
    }
}

4、后台线程
public final void setDaemon(boolean on)

​ 用户线程:没有调用Daemon方法的线程

​ 守护线程:调用了Daemon方法的线程

​ 在启动之前,设置一下,若一个进程中没有用户线程,守护线程也没有存在的必要。

class DaemonThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 200; i++){
            System.out.println(getName()+" - "+i);
        }
    }
}

public class ThreadBaemonDemo1 {
    public static void main(String[] args) {
        DaemonThread d1 = new DaemonThread();
        DaemonThread d2 = new DaemonThread();
        DaemonThread d3 = new DaemonThread();

        d1.setName("刘备");
        d2.setName("关羽");
        d3.setName("张飞");
        d2.setDaemon(true);
        d3.setDaemon(true);

        d1.start();
        d2.start();
        d3.start();

    }
}

​ 这个例子的大概意思是,张飞、关羽线程在守护刘备线程,在刘备线程执行完后,张飞、关羽线程无论有没有执行完毕都会停止执行,而结果中之所以还有一段结果,是因为在计算机的一个小的时间片中,停止的信号还未传达到,所以还会执行几条。

5、中断线程

public final void stop():使用stop()方法,线程会直接结束,此方法已被弃用

public void interrupt():使用interrupt()方法,当线程睡眠时,会打断睡眠,提示异常,并执行完后续的语句

class StopThread extends Thread{
    @Override
    public void run() {
        System.out.println(getName()+"睡着了。。。。");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(getName()+"睡醒了。。。。");
    }
}
public class ThreadStopDemo1 {
    public static void main(String[] args) {
        StopThread s1 = new StopThread();
        s1.setName("🐱");
        s1.start();
        try {
            Thread.sleep(2000);
//            s1.stop();//已经被弃用了
            s1.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

posted on 2024-08-19 21:56  宁静绿湖  阅读(24)  评论(0)    收藏  举报