多线程常用操作

线程命名与取得

多线程的运行状态是不确定的,所以对于多线程操作必须有一个明确标识出线程对象的信息,这个信息往往通过名称来描述。在Thread类中提供有如下的线程名称方法:
在这里插入图片描述

class MyThread implements Runnable {
    @Override
    public void run() {}
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"线程1");
        thread.start();
        System.out.println(thread.getName());

        Thread thread1 = new Thread(new MyThread());
        thread1.start();
        thread1.setName("线程2");
        System.out.println(thread1.getName());

        Thread thread2 = new Thread(new MyThread());
        thread2.setName("线程3");
        thread2.start();
        System.out.println(thread2.getName());
        
        thread2.setName("子线程3");
        System.out.println(thread2.getName());
    }
}

如何证明mian方法也是一个线程?

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.run();
    }
}


Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\Java\code\out\production\code" www.bit.java.TestThread
main

Process finished with exit code 0

线程休眠(sleep方法)

线程休眠:指的是让线程暂缓执行一下,等到了预计时间之后再恢复执行。

public static native void sleep(long millis) throws InterruptedException

线程休眠会交出CPU(变回阻塞状态),让CPU去执行其他的任务,睡眠结束后返回就绪状态。但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。
休眠时间使用毫秒作为单位

class MyThread implements Runnable {
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
    }
}

线程让步(yield()方法)

暂停当前正在执行的线程对象,并执行其他线程。
意思就是调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会
注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

class MyThread implements Runnable {
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+","+i);
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}

join()方法

等待该线程终止。意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行完毕之后在开始执行主线程。
join()方法只是对Object提供的wait()做的的一层包装而已。
join()方法变回阻塞状态结束后返回就绪状态会释放锁


    class MyThread implements Runnable {
    @Override
    public void run() {
        try{
            System.out.println("主线程睡眠前的时间");
            TestThread.printTime();
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName());
            System.out.println("睡眠结束的时间");
            TestThread.printTime();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyThread(),"子线程");
        thread.start();
        System.out.println(Thread.currentThread().getName());
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("代码结束");
    }
    public static void printTime() {
        Date date=new Date();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = dateFormat.format(date);
        System.out.println(time);
    }
}


Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\Java\code\out\production\code" www.bit.java.TestThread
main
主线程睡眠前的时间
2018-11-14 13:07:10
子线程
睡眠结束的时间
2018-11-14 13:07:12
代码结束

Process finished with exit code 0

5线程停止

多线程中有三种方式可以停止线程。

  • 设置标记位,可以是线程正常退出。
class MyThread implements Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println(Thread.currentThread().getName() + "第" + ++i + "次执行");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程");
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.setFlag(false);
        System.out.println("代码结束");
    }
}


Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\Java\code\out\production\code" www.bit.java.TestThread
子线程第1次执行
子线程第2次执行
子线程第3次执行
子线程第4次执行
子线程第5次执行
代码结束

Process finished with exit code 0

  • 使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了

为什么说不安全呢?因为stop会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,假如一个线程正在执行:synchronized void { x = 3; y = 4;} 由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中, 它也会马上stop了,这样就产生了不完整的残废数据。

class MyThread implements Runnable {
    @Override
    public void run() {
        int i = 0;
        while (true) {
            System.out.println(Thread.currentThread().getName() + "第" + ++i + "次执行");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程");
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.stop();
        System.out.println("代码结束");
    }
}
  • 使用Thread类中的一个interrupt() 可以中断线程。

调用Thread类的interrupt()方法,只是将线程状态置为中断状态而已,他不会中断一个正在运行的线程。此方法只是给受阻塞的线程传递一个中断信号,程序可以根据此信号来判断是否需要终止。

具体而言,这个方法只会给线程设置一个为true的中断标志(中断标志只是一个布尔类型的变量),而设置之后,则根据线程当前的状态进行不同的后续操作。如果,线程的当前状态处于非阻塞状态,那么仅仅是线程的中断标志被修改为true而已;如果线程的当前状态处于阻塞状态,那么在将中断标志设置为true后,还会有如下三种情况之一的操作:
当线程中使用了sleep、wait、join()导致此线程阻塞,则interrupt()会在线程中抛出InterruptException,并且将线程的中断状态由true置为false。
如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,而在此基础上,一旦进入阻塞状态,则按照阻塞状态的情况来进行处理。

通过上面的分析,我们可以总结,调用线程类的interrupted方法,其本质只是设置该线程的中断标志,将中断标志 设置为true,并根据线程状态决定是否抛出异常。因此,通过interrupted方法真正实现线程的中断原理是:开发人员根据中断标志的具体值,来决定如何退出线程。

class MyThread implements Runnable {

    @Override
    public void run() {
        int i = 0;
        while (true) {
            try {
                /**
                 * 这里阻塞之后,线程被调用了interrupte()方法,
                 * 清除中断标志,就会抛出一个异常
                 * java.lang.InterruptedException                    */
                Thread.sleep(1000);
                boolean bool = Thread.currentThread().isInterrupted();
                if(bool){
                    System.out.println("非阻塞状态下执该操作...线程状态:"+bool);
                    break;
                }
                System.out.println("第"+(++i)+"次执行,"+bool+",线程名称为:"+Thread.currentThread().getName());
            } catch (Exception e) {
                System.out.println("退出了");
                /**
                 * 这里退出阻塞状态,且中断标志被系统会自动清除
                 * 并且重新设置为false,所以此处bool为false
                 */
                boolean bool = Thread.currentThread().isInterrupted();
                System.out.println(bool);
                //退出run方法,中断进程
                return;
            }
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程");
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        System.out.println("代码结束");
    }
}


Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\Java\code\out\production\code" www.bit.java.TestThread
第1次执行,false线程名称为:子线程
第2次执行,false线程名称为:子线程
第3次执行,false线程名称为:子线程
第4次执行,false线程名称为:子线程
代码结束
退出了
false

Process finished with exit code 0

线程优先级

线程的优先级指的是,线程的优先级越高越有可能先执行,但仅仅是有可能而已。

  • 设置优先级
public final void SetPriority(int newPriority)
  • 取得优先级
public final int getPriority()

对于优先级设置的内容可以通过Thread类的几个常量来决定

  1. 高优先级:public final static int MAX_PRIORITY = 10;
  2. 中等优先级:public final static int NORM_PRIORITY = 5;
  3. 低优先级:public final static int MIN_PRIORITY = 1;
public class TestThread {
    public static void main(String[] args) {
        Runnable runnable = () -> System.out.println(Thread.currentThread().getName());
        Thread thread1 = new Thread(runnable,"子线程1");
        Thread thread2 = new Thread(runnable,"子线程2");
        Thread thread3 = new Thread(runnable,"子线程3");
        thread1.setPriority(Thread.MIN_PRIORITY);
        thread2.setPriority(Thread.MAX_PRIORITY);
        thread3.setPriority(Thread.NORM_PRIORITY);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

主方法是一个线程,那么主线程的优先级是什么呢?

主方法只是一个中等优先级,为5

public class TestThread {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getPriority());   //5 
    }
}

线程具有继承性

只是继承优先级而已。从A线程启动B线程,则B和A的线程优先级是一样的

class A implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+","+Thread.currentThread().getPriority());
        new Thread(new B(),"线程B").start();
    }
}
class B implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+","+Thread.currentThread().getPriority());
    }
}
public class TestThread {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+","+Thread.currentThread().getPriority());
        Thread thread = new Thread(new A(),"线程A");
        thread.setPriority(Thread.MAX_PRIORITY);
        thread.start();
    }
}

Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\Java\code\out\production\code" www.bit.java.TestThread
main,5
线程A,10
线程B,10

守护线程

守护线程是一种特殊的线程,它属于是一种陪伴线程。简单点说 java 中有两种线程:用户线程和守护线程。可以通过isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。典型的守护线程就是垃圾回收线程注意:主线程main是用户线程
只要当前JVM进程中存在任何一个非守护线程没有结束,守护线程就在工作;只有当后一 个非守护线程结束时,守护线程才会随着JVM一同停止工作。
Thread类提供setDaemon()将用户线程设置为守护线程

class MyThread implements Runnable {
    @Override
    public void run() {
        while(true){
            System.out.println(Thread.currentThread().getName()+"是否为守护线程"+Thread.currentThread().isDaemon());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + "中断线程了");
                return;
            }
        }
    }
}
public class TestThread {
    public static void main(String[] args) throws InterruptedException{
        Thread thread1 = new Thread(new MyThread(),"线程1");
        thread1.setDaemon(true);

        Thread thread2 = new Thread(new MyThread(),"线程2");
        thread1.start();
        thread2.start();

        Thread.sleep(3000);
        thread2.interrupt();
        Thread.sleep(5000);
        System.out.println("代码结束");
    }
}

Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\Java\code\out\production\code" www.bit.java.TestThread
线程1是否为守护线程true
线程2是否为守护线程false
线程1是否为守护线程true
线程2是否为守护线程false
线程2是否为守护线程false
线程1是否为守护线程true
线程2中断线程了
线程1是否为守护线程true
线程1是否为守护线程true
线程1是否为守护线程true
线程1是否为守护线程true
线程1是否为守护线程true
代码结束

Process finished with exit code 0

从上面的代码可以看出来,B是用户线程当它中断了之后守护线程还没有结束,是因为主线程(用户线程)还没有结束,所以说明是所有的用户线程结束之后守护线程才会结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值