线程的方法

线程的方法

1.获取当前线程对象:CurrentThread()

    @Test
    public void bb()  {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());//打印  main
    }

2.currentThread().setName和currentThread().getName

    @Test
    public void bb()  {
        Thread.currentThread().setName("heihei");
        String name = Thread.currentThread().getName();
        System.out.println(name); // 打印 heihei
    }

3.currentThread().isAlive()

判断当前线程是否正在执行

    @Test
    public void bb()  {
        MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
        Thread t = new Thread(mt,"线程");        // 实例化Thread对象
        System.out.println("线程开始执行之前 --> " + t.isAlive()) ;     // 打印结果:线程开始执行之前 --> false
        t.start() ;    // 启动线程
        System.out.println("线程开始执行之后 --> " + t.isAlive()) ;     // 打印结果:线程开始执行之前 --> true
    }

4.start()与run()

调用start()方法才是 启动一个新的线程。

调用run()方法只是主线程调用了一个类的一个普通方法.并没有开启一个新线程.

    @Test
    public void bb()  {
        MyThread myThread = new MyThread();
        myThread.start();  //打印  Thread-2运行了
        myThread.run();  //打印   main方法运行了
    }

5.join()/join(long millis)

将两个线程绑定在一起,看成是共同体,B线程执行完成后,必然执行A线程.

join()就是A无限期等待,当B线程执行完,A线程才执行

join(1000)就是A只等待1000毫秒

如果B 500毫秒执行完了,那么 A就直接结束等待时间,直接被唤醒

如果A等待1000毫秒后,B还没执行完,那A也不等了,就直接被唤醒和B一块并发执行

底层其实就是A线程被wait,下面是底层代码

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {//只要B线程还没结束,A线程就会一直阻塞
            wait(0);//这里的wait调用的本地方法。
        }
    } else {//等待一段指定的时间
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

下面是例子

    @Test
    public void bb()  {
        MyBThread myThread = new MyBThread();
        myThread.start();
        for (int i = 0; i < 15; i++) {
            if(i>5){
                try{
                    myThread.join() ;    // 线程强制运行
                }catch(InterruptedException e){}
            }
            System.out.println("Main线程运行 --> " + i) ;
        }
    }

}
class MyBThread extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 15; i++) {
            System.out.println(Thread.currentThread().getName()+"运行了,i="+i);
        }

    }
}
Main线程运行 --> 0
Main线程运行 --> 1
Main线程运行 --> 2
Main线程运行 --> 3
Main线程运行 --> 4
Main线程运行 --> 5
Thread-2运行了,i=0
Thread-2运行了,i=1
Thread-2运行了,i=2
Thread-2运行了,i=3
Thread-2运行了,i=4
Thread-2运行了,i=5
Thread-2运行了,i=6
Thread-2运行了,i=7
Thread-2运行了,i=8
Thread-2运行了,i=9
Thread-2运行了,i=10
Thread-2运行了,i=11
Thread-2运行了,i=12
Thread-2运行了,i=13
Thread-2运行了,i=14
Main线程运行 --> 6
Main线程运行 --> 7
Main线程运行 --> 8
Main线程运行 --> 9
Main线程运行 --> 10
Main线程运行 --> 11
Main线程运行 --> 12
Main线程运行 --> 13
Main线程运行 --> 14

6.yield()

yield() 暂停当前方法,释放自己拥有的CPU,线程进入就绪状态。它能让当前线程由“运行状态”进入到“就绪状态”,然后和其他优先级比它高的或者和它相同的线程一起去重新争抢cpu的使用.

优先级高的线程抢到cpu的概率较大,但是不一定会第一个抢到,  因为这还和操作系统的调度和cpu的执行有关系.  建议少用.

7.sleep(long millis)

线程休眠:让执行的线程暂停一段时间,进入计时等待状态。
static void sleep(long millis):调用此方法后,当前线程放弃 CPU 资源,在指定的时间内,sleep 所在的线程不会获得可运行的机会,此状态下的线程不会释放同步锁。
该方法更多的是用来模拟网络延迟,让多线程并发访问同一资源时的错误效果更加明显。

8.wait()和notify()/notifyAll()

wait()/wait(long timeout)/wait(long timeout, int nanos)

先看一看wait的三个重载方法

  • public final void wait() throws InterruptedException
  • public final void wait(long timeout) throws InterruptedException
  • public final void wait(long timeout, int nanos) throws InterruptedException

方法参数

timeout - 等待时间(以毫秒为单位)。

nanos - 额外等待时间(以纳秒为单位)。

wait()相当于调用wait(0),0表示永远不超时。让当前线程处于等待状态,只有调用对象的notify或者notifyAll才能将其唤醒.

wait(1000):等待1000毫秒, 让当前线程处于计时等待状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数 timeout设置的超时时间才能将其唤醒.

wait(1000,50):等待1000毫秒+50纳秒, 让当前线程处于计时等待状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数 timeout 加上 nanos 设置的超时时间才能将其唤醒.

notify()/notifyAll()

唤醒:notify()-随机唤醒wait的一个线程,notifyAll()-唤醒所有线程
注意:此方法需和wait()成对使用,必须在同步代码块或同步方法中

上面的方法必须在同步代码块或同步方法中

每一个对象都有一个跟它关联的monitor,只有获取到对象的monitor才能调用对象的wait方法和调用对象的notify和notifyAll方法。也就是说wait,notify,notifyAll都必须在对象的synchronized同步方法里面调用。如果wait没有在对象的synchronized同步块里面执行会抛出

java.lang.IllegalMonitorStateException

 结束线程的方法

1.线程正常自动结束

2.使用标准位终结线程

一般 run()方法执行完,线程就会正常结束,然而,常常有些线程是伺服线程。它们需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,例如: 最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while 循环是否退出,代码示例:

@RestController
@RequestMapping("/test")
public class Docx4jOfficeFileToPDF {
        public static void main(String args[]) throws InterruptedException {
            MyBThread mt = new MyBThread() ;
            mt.start();
            Thread.sleep(1);//主线程等待1ms
            mt.exit = true; //修改标志位,退出线程
        }
}
class MyBThread extends Thread{
    //volatile修饰符用来保证其它线程读取的总是该变量的最新的值
    public volatile boolean exit = false;
    @Override
    public void run() {
        int i =1;
        while(!exit){
            System.out.println(i++);
        }
        System.out.println("结束");
    }
}

定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false.在定义exit 时,使用了一个 Java 关键字 volatile,这个关键字的目的是使 exit 同步,也就是说在同一时刻只 能由一个线程来修改exit的值。 

 3.interrupt()

 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。

① 如果线程使用了 sleep,同步锁的 wait,socket 中的 receiver,accept 等方法时, 会使线程处于阻塞状态。当sleep()等方法和interrupt() 方法相遇时.sleep()等方法会抛出 InterruptException 异常,并清除掉线程的中断标识.

② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,丝毫不受影响。

所以我们只有手动去停止线程,我们需要配合下面的两个方法,来手动写停止逻辑代码,以达到手动停止线程的目的

public boolean Thread.isInterrupted() //判断是否被中断
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态

实验得知:

1.在线程sleep()阻塞的时候, 线程再去调 interrupt()方法,会抛出 InterruptException 异常

2.在线程调完interrupt()方法,有中断标识的时候,  线程再去调sleep()方法.也会抛出InterruptException 异常

因此,实验得出下面的代码100%能结束线程.

public class Docx4jOfficeFileToPDF {
    public static void main(String args[]) throws InterruptedException {
        MyBThread mt = new MyBThread() ;
        mt.start();//子线程执行
        mt.interrupt();//给子线程加上中断标志

    }
}
class MyBThread extends Thread{
    @Override
    public void run() {
        while (true){
            try{
                Thread.sleep(500000);//阻塞过程捕获中断异常来退出
            }catch(InterruptedException e){
                e.printStackTrace();
                break;//捕获到异常之后,执行break跳出循环,相当于结束子线程
            }
        }
    }
}

或者用interrupt()当做标准位终止线程的那种方式

@RestController
@RequestMapping("/test")
public class Docx4jOfficeFileToPDF {
        public static void main(String args[]) throws InterruptedException {
            MyBThread mt = new MyBThread() ;
            mt.start();
            mt.interrupt(); //修改标志位,退出线程
        }
}
class MyBThread extends Thread{
    @Override
    public void run() {
        int i =1;
        while(!isInterrupted()){
            System.out.println(i++);
        }
        System.out.println("结束");
    }
}

 4.stop ()

此方法已被弃用,不安全.

为什么弃用stop:

  1. 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
  2. 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
  3. stop()方法被try-catch()后会失效.

例如,存在一个对象 u 持有 ID 和 NAME 两个字段,假如写入线程在写对象的过程中,只完成了对 ID 的赋值,但没来得及为 NAME 赋值,就被 stop() 导致锁被释放,那么当读取线程得到锁之后再去读取对象 u 的 ID 和 Name 时,就会出现数据不一致的问题

@RestController
@RequestMapping("/test")
public class Docx4jOfficeFileToPDF {
        public static void main(String args[]){
            MyBThread mt = new MyBThread() ;
            mt.start();
        }
}
class MyBThread extends Thread{
    @Override
    public void run(){
        System.out.println("运行了111");
        this.stop();
        System.out.println("运行了222");
    }
}
运行了111

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值