多线程——线程基础

目录

1、继承Thread类

2. 实现Runnable接口

3. currentThread() 方法

4. isAlive() 方法

5. sleep()  方法

6. getId() 方法

7. 停止线程

8. interrupt() 停止一个线程——抛出异常法

9.  interrupt() 停止一个线程——阻塞中停止

10.  interrupt() 停止一个线程——return返回 

11. 挂起线程和唤醒线程——suspend、resume

12. yield() 方法

13. 守护线程


CPU执行的代码:就是说这个线程要做什么,就是代码。

代码操作的数据:

虚拟处理机:不是说多线程是并行运行的吗?那么多个线程同时运行,就需要有多个处理机去处理,而CPU只有一个,那么就通过软件来模拟出过个虚拟的处理机。

main()方法是程序的入口,那么调用main()方法是线程是由JVM创建的线程,名字叫main。

 

1、继承Thread类

public class BBB extends Thread{
    @Override
    public void run(){
        System.out.println("hellooooo");
    }
}
public class Test{
    public static void main(String[] args){
        BBB b = new BBB();
        b.start();
    }
}

BBB类继承了Thread类,重写了run()方法,run()方法中的代码就是此线程要执行的代码,但是要通过start()方法来触发run()方法的执行,也就是说必须要调用start()方法才能让线程执行起来。

2. 实现Runnable接口

public class BBB implements Runnable{
    @Override
    public void run(){
        System.out.println("hellooooo");
    }
}
public class Test{
    public static void main(String[] args){
        BBB b = new BBB();
        Thread t = new Thread(b);
        t.start();
    }
}

通过实现Runnable接口的方式来实现线程。 

 

3. currentThread() 方法

Thread.currentThread() 方法是获取调用当前代码段的线程,举个例子:

public class Test {
    public static void main(String[] args) {
        ThreadOne threadOne = new ThreadOne();
        threadOne.run();
    }
}

public class ThreadOne extends Thread{
    public ThreadOne(){
        System.out.println("构造方法:" + Thread.currentThread().getName());
    }
    @Override
    public void run() {
        System.out.println("run方法:" + Thread.currentThread().getName());
    }
}

运行结果:

分析: new ThreadOne()创建线程对象的时候,是main线程调用的,所以打印出来的也是main。  第二个run()方法也是main线程调用的,所以打印的也是main。

注意:threadOne.run() 和 threadOne.start()  是有区别的,run()单纯是调用run方法,而start()是启动一个线程,然后线程去执行run方法。

我们改一下:

public class Test {
    public static void main(String[] args) {
        ThreadOne threadOne = new ThreadOne();
        threadOne.start();
    }
}

public class ThreadOne extends Thread{
    public ThreadOne(){
        System.out.println("构造方法:" + Thread.currentThread().getName());
    }
    @Override
    public void run() {
        System.out.println("run方法:" + Thread.currentThread().getName());
    }
}

运行结果:

此时的第二个打印出来的就是Thread-0。这个名字是线程默认的线程名初始化规则生成的。因为start()方法是启动了线程,然后线程执行的run方法,所以当然是新线程的线程名咯。

 

4. isAlive() 方法

判断一个线程是否还“存活”,存活状态是指线程启动了,但是还没有终止的这段时间。

5. sleep()  方法

让当前线程休眠多少毫秒。那么当前线程到底是什么线程呢? 就是currentThread() 返回的线程。

6. getId() 方法

每一个线程不仅有线程名,还有一个唯一的标志ID, getId() 方法就是获取当前线程的唯一ID号。

7. 停止线程

stop() 方法可以停止一个线程,但是不安全,已被淘汰。 大多数线程停止操作通过 interrupt() 方法,它不能终止一个正在运行的线程,需要一些参数判断才能。

interrupt() 方法。 详细说一下,这个方法只是改变一个线程的中断标志,仅此而已,线程的中断标志(true 或 false),true表示中断状态,false表示未中断状态,调用interrupt() 方法就是将中断标志设置为true,当一下线程正在正常运行的时候,是不会去检查这个中断标志的,只有当阻塞的时候,才会频繁去检查这个中断标志,wait()、join()、sleep() 方法都会使线程进入阻塞,如果阻塞期间,该线程调用了interrupt() 方法,那么检查到中断标志已经变为了true,此时出错了,因为本来我线程只是阻塞了,还没有终止呢,但是此时检查到线程已经处于中断状态,就要抛出异常,那么java虚拟机会将中断标志改为false,等抛出了异常,这个线程就算退出了。

interrupted() 方法,线程的这个方法是用于判断“当前线程”是否已经中断,实际就是检查“中断标志”,将中断标志返回。注意:这个方法调用一次后,会清理掉中断标志,比如,当前线程调用了interrupt() 方法,中断标志是true,此时又调用interrupted() 方法,返回值为true,但是接着又调用interrupted() 方法,这个方法返回值就是 false,因为第一个调用完了之后,就清理掉中断标志了(中断标志变为false)。

isInterrupted() 方法。调用这个方法的线程对象(就是线程)是否已经处于中断状态,返回也是true 或 false, 但是isInterrupted() 方法不会清理中断标志。

8. interrupt() 停止一个线程——抛出异常法

举例说明:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        InterruptOne interruptOne = new InterruptOne();
        Thread thread = new Thread(interruptOne);
        thread.start(); 启动线程
        Thread.currentThread().sleep(2); main线程停止2毫秒,就是不要马上执行interrupt方法,要等interruptOne执行2毫秒的时候,在interrupt
        thread.interrupt();
    }
}

public class InterruptOne extends Thread {
    @Override
    public void run() {
        super.run();
        for(int i = 0; i <= 1000; i ++){
            if(Thread.interrupted()){
                System.out.println("线程终止!");
                break;
            }
            System.out.println("i = " + i);
        }
        System.out.println("依然继续运行着,至此才结束");
    }
}

运行结果:

分析:说明interrupt() 方法只是改变了线程的中断标志,而并不会影响线程的继续运行(除了阻塞)。

用抛出异常的方法让线程终止

public class Test {
    public static void main(String[] args) throws InterruptedException {
        InterruptException interruptException = new InterruptException();
        Thread thread = new Thread(interruptException);
        thread.start();
        Thread.currentThread().sleep(4);
        thread.interrupt();
    }
}

public class InterruptException extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            for(int i = 0; i <= 1000; i ++){
                if(Thread.interrupted()){
                    System.out.println("线程终止!");
                    throw new InterruptedException();
                }
                System.out.println("i = " + i);
            }
            System.out.println("依然继续运行着,至此才结束");
        }catch (Exception e){
            System.out.println("抛出异常导致线程终止");
        }

    }
}

运行结果:

分析:这次是直接throw new InterruptException() 抛出异常的方法,直接终止线程的剩余部分执行。

9.  interrupt() 停止一个线程——阻塞中停止

阻塞包括wait()、sleep()、join()方法,此处就以sleep() 为例。

public class Test {
    public static void main(String[] args) throws InterruptedException {
        InterruptSleep interruptSleep = new InterruptSleep();
        Thread thread = new Thread(interruptSleep);
        thread.start();
        Thread.sleep(100); main线程睡眠100毫秒,目的是让interruptSleep线程要跑起来,并且进入睡眠阻塞状态
        thread.interrupt();
    }
}

public class InterruptSleep extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("开始了");
            Thread.sleep(1000);
            System.out.println("结束了");
        }catch (Exception e){
            System.out.println("线程在睡眠中就抛出了异常");
        }
    }
}

运行结果:

分析:因为在interruptSleep线程睡眠期间,它的中断标志变为了true,就会抛出异常,所以结果如上。

10.  interrupt() 停止一个线程——return返回 

public class Test {
    public static void main(String[] args) throws InterruptedException {
        InterruptOne interruptOne = new InterruptOne();
        Thread thread = new Thread(interruptOne);
        thread.start(); 启动线程
        Thread.currentThread().sleep(2); main线程停止2毫秒,就是不要马上执行interrupt方法,要等interruptOne执行2毫秒的时候,在interrupt
        thread.interrupt();
    }
}

public class InterruptOne extends Thread {
    @Override
    public void run() {
        super.run();
        for(int i = 0; i <= 1000; i ++){
            if(Thread.interrupted()){
                System.out.println("线程终止!");
                return;
            }
            System.out.println("i = " + i);
        }
        System.out.println("依然继续运行着,至此才结束");
    }
}

在线程的run方法中,直接使用return,也可以达到立即终止线程的效果。

11. 挂起线程和唤醒线程——suspend、resume

这两个方法已经是过期方法,因为方法存在不安全。

占用公共资源(死锁、阻塞)。这是因为suspend() 方法会使一个线程处于挂起状态,什么都不执行,但是却没有结束终止,试想,有公共资源的情况下,多个线程都要访问这个公共资源,此时A线程访问到了,但是A线程挂起了,那么其它线程就无法再访问这个资源了,只要A线程还处于挂起状态(不释放资源的锁),那么其它要访问资源的线程都要阻塞在那,什么也做不了。

数据不同步。线程也许改变了部分数据,突然挂起,那么剩余部分数据仍未改变,此时的数据是不一致的,如果此时有其它线程使用这些数据的话,就会导致不正确的结果。

12. yield() 方法

这个方法是让线程放弃cpu资源,但是放弃多久呢?不确定,只是让线程放弃当前占用的cpu资源,也许放弃了之后,立马又是此线程占用cpu。

13. 守护线程

线程分为两种:守护线程、非守护线程(用户线程)。

守护线程就是一旦启动,就会一直运行到最后彻底结束了,它才结束。比如:java的垃圾收集器,只要java程序运行着,那么垃圾收集器就一直运行着,当所有java程序都运行完了,垃圾收集器才运行结束。

如果系统中还有非守护线程在运行,那么守护线程就不能终止,除非所有的非守护线程就运行结束了,没有其它非守护线程在运行了,那么此时守护线程才终止结束。

设置方法: 线程对象.setDaemon( true );

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值