Thread

线程和线程之间

堆内存和方法区内存是共享的,但是栈内存独立,一个线程一个栈。

假设启动10个线程,或有10个栈空间,每个栈和每个栈互不干扰,各自执行各自的,这就是多线程并发。

启动分支线程两种方式:

方式一:

继承 Thread类,重写run方法(run方法不需要手动调用java虚拟机会自动调用)

class MYThread extends Thread{
    @Override
    public void run() {
        super.run();
    }
}

启动一个分支线程

public class TEST {
    public static void main(String[] args) {
        // 创建一个分支线程对象
        MYThread myThread = new MYThread();
        myThread.start();
    }
}

start() 方法的作用是:启动一个分支线程,在JVM中,开辟一个新的栈空间,这段代码,任务完成之后,瞬间就结束了,这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开辟出来,start() 方法就结束了,线程就启动成功了。启动成功的线程会自动调用run方法,并且run方法在分支栈底部(压栈)。

run方法在分支栈的栈底部,main方法在主栈的栈底部。run和main是平级的。

方式二:

实现Runnable接口

public class TEST {
    public static void main(String[] args) {
        // 创建线程对象
        Thread thread = new Thread(new MYThread());
        // 启动线程
        thread.start();
    }
}
// 编写一个类,实现Runnable接口,实现run方法
class MYThread implements Runnable{
    @Override
    public void run() {
        System.out.println("1");
    }
}
// lambda表达式
public class TEST {
    public static void main(String[] args) {
        // 创建线程对象 lambad
        Thread thread = new Thread(() -> {
            int r = 50;
            for (int i = 0; i < 10000; i++) {
                System.out.println("子线程线程");
            }
        });
        // 启动线程
        thread.start();

        for (int i = 0; i < 10000; i++) {
            System.out.println("main线程");
        }
    }
}

线程的生命周期

一共分五个状态

新建状态 -> 就绪状态 -> 运行状态 -> 阻塞状态 -> 死亡状态。

 

 线程名字

1、获取线程名字

线程对象.getName() 

2、修改线程对象的名字

线程对象.setName()

public class Lv20210810 {
    /**
     * 获取线程对象
     * 获取线程对象的名字
     * 修改线程对象
     * @param args
     */
    public static void main(String[] args) {
        MyTread myTread = new MyTread();
        System.out.println(myTread.getName()); // 线程对象默认名字为:Thread-0,以此Thread-1 ··· ···
        myTread.setName("123"); // 修改线程名字
        System.out.println(myTread.getName()); // 123
        myTread.start();
    }
}
class MyTread extends Thread {
    @Override
    public void run() {
        System.out.println("子线程执行了");
    }
}

3、获取当前线程名字

Thread t = Thread.currentThread()

上边代码出现在哪,获取的就是当前线程的对象。

例:出现在main方法中,获取的就是当前主线程的对象,出现在子线程里,获取的就是子线程对象。

public static void main(String[] args) {
  System.out.println(Thread.currentThread().getName()); // main
}
public class Lv20210810 {
    public static void main(String[] args) {
        MyTread myTread = new MyTread();
        myTread.start();
    }
}
class MyTread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()); // Thread-0
    }
}

线程的sleep

static void sleep(long 毫秒) 

Thread.sleep(1000)

线程的阻塞状态。

(1)静态方法
(2)参数是毫秒数
(3)作用:让当前线程进入休眠,进入 "阻塞状态",放弃占有的CPU时间片,让给其他线程使用。

// 3秒钟之后才会打印子线程名称
public class Lv20210810 
    public static void main(String[] args) {
        MyTread myTread = new MyTread();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myTread.start();
    }
}
class MyTread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()); // Thread-0
    }
}

面试题:

1、

下边代码会不会阻塞 t线程的执行?

下边考察两个点:

(1)Thread.sleep() 方法在哪里执行,那么当前的线程会阻塞,下边在main方法中执行,那么它会阻塞main方法的执行。
(2)在java中静态变量可以用类来调用,也可以用对象类调用,但是,java中推荐用类名调用以区别实例方法或实例变量。

下边代码执行结果:先执行 "子线程执行",过3秒钟输出 "main方法执行了"

public class Lv20210810 {
    public static void main(String[] args) {
        MyTread t = new MyTread();
        t.setName("t");
        t.start();
        try {
            t.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main方法执行了");
    }
}
class MyTread extends Thread {
    @Override
    public void run() {
        System.out.println("子线程执行"); 
    }
}

终止线程休眠

线程对象.interrupt ()

这种终止方式是靠抛出异常来完成的。

下边代码:先输出 "start" ,三秒钟之后抛出异常,在输出 "end"

public class Lv20210810 {
    public static void main(String[] args) {
        MyTread t = new MyTread();
        t.setName("t");
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 终止名字为t线程的睡眠
        t.interrupt();
    }
}
class MyTread extends Thread {
    @Override
    public void run() {
        System.out.println("start");
        try {
            Thread.sleep(1000L * 60 * 60 * 24 * 365) ;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end");
    }
}

合理的终止线程执行

加锁的方式

下边代码,三秒钟之后,我们把down改为false,此时会结束掉 myThread线程的执行。

public class Lv20210810 {
    public static void main(String[] args) {
        MyTread myTread = new MyTread();
        myTread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myTread.down = false;
    }
}
class MyTread extends Thread {
    boolean down = true;
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(down) {
                System.out.println(i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else {
                return;
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值