javaSE高级开发多线程——3 多线程的常用操作方法

1.线程命名于取得
当我们没有给线程取名字的时候,我们调用getName()函数,会发现系统会自定的给线程起名字为:thread-0,thread-1…显然这样是不好的,当我们又很多线程的时候,线程的名字如果不能见名思意的话,我们就会混淆,所以建议,我们只用线程就给它取名字,线程起名字通过:setName()函数的方法。

    public static void main(String[] args) {
        ThreadTool task=new ThreadTool();
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                //直接实现了我们代理类里面的功能,不需要再创建一个类了
                task.print("hello","nihao");
            }
        });
        thread.start();
//        //系统自定义的名字
//        System.out.println(thread.getName());
          //我们自己给线程起名字
        thread.setName("线程-处理PrintInfo");
        System.out.println(thread.getName());
    }

2.共享变量的两种方式

package com.wschase.xianchengjianjie;

/**
 * Author:WSChase
 * Created:2019/1/8
 */
public class Thread3 extends Thread {
    private static int tick=10;//将它变为类的属性就可以实现共享了

    @Override
    public void run() {
        while(tick>0){
            System.out.println(this.getName()+"剩余:"+tick--+"张票");
        }
    }

    public static void main(String[] args) {
        //(1)这个是使用Thread来实现的
//        Thread3 thread1=new Thread3();
//        thread1.setName("Thread-A");
//        Thread3 thread2=new Thread3();
//        thread2.setName("Thread-B");
//        thread1.start();
//        thread2.start();
        //(2)使用Runnable来实现
        Runnable runnable=new Runnable() {
            private int tick=10;
            @Override
            public void run() {
                while(tick>0){
                    //ThreadcurrentThread():表示获得当前线程的名字
                    System.out.println(Thread.currentThread()+"剩余:"+tick--+"张票");
                }
            }
        };
        new Thread(runnable,"Thread-A").start();
        new Thread(runnable,"Thread-B").start();
    }
}

通过上面的两种方式我们可以看到,Runnable是实现变量共享的方式更加的好、安全。
3.线程命名与取得

package com.wschase.xianchengjianjie;

/**3.多线程的常用操作方法
 * Author:WSChase
 * Created:2019/1/8
 */
public class ThreadTool {
    //这是一个普通任务
    public void print(Object ... args){
        for(int i=0;i<args.length;i++){
            System.out.println(args[i]);
        }
    }

    public static void main(String[] args) {
        //我们的main方法就是我们的主线程
        ThreadTool task=new ThreadTool();
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                //直接实现了我们代理类里面的功能,不需要再创建一个类了
                task.print("hello","nihao");
            }
        });
        thread.start();
//        //系统自定义的名字
//        System.out.println(thread.getName());
          //我们自己给线程起名字
        thread.setName("线程-处理PrintInfo");
        System.out.println(thread.getName());
    }
}

4.线程的各个状态
需要注意的是Sleep方法,并不会释放资源。在多线程里面我们只用资源的时候采用的方法,都是锁定的方法,当我锁定以后别人没有打开这把锁的钥匙,所以别人是使用不了的,必须等到我把资源释放以后才可以使用。但是资源的分配并不是说有资源就可以使用的,还是存在资源竞争。当一个线程运行完成以后这个线程就死亡了。
5.休眠(Sleep)方法
休眠的概念:首先我们需要知道,线程休眠指的是让程序暂停一下,等到休眠时间完成以后我们再进行程序的执行。
但是需要我们注意的是,线程的休眠是交出CPU,让CPU可以取执行其他的任务,但是它并不会将自己资源的锁交出去,所以就算是处于休眠状态,但是这个线程占有的资源并不会释放的,其他线程并不可以使用该线程的资源。

package com.wschase.xianchengjianjie;

import java.time.LocalDateTime;
import java.util.Locale;

/**
 * Author:WSChase
 * Created:2019/1/8
 */
public class TestSleep {
    public static void main(String[] args) {
        //最简洁的写法
        new Thread(()->{
            while (true){
                try {
                    Thread.sleep(1000);//单位是毫秒
                    System.out.println("当前时间"+LocalDateTime.now());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread-A").start();
    }
}

6.线程让步yield()
线程让步有几个特点:
(1)它与sleep()方法是一样的,只是让出CPU时间片段,但是并不会释放锁。
(2)可以获得让出CPU时间片段的必须是和该线程有相同权限的线程。
(3)它让出权限的时间并不是一定的,是不定的,并不受它的控制。
(4)这是它和sleep的区别:使用线程让步yeild()方法并不会到线程的阻塞状态,而是直接到线程的就绪状态,等到下次直接到线程的运行状态。

package com.wschase.xianchengjianjie;

/**线程让步
 * Author:WSChase
 * Created:2019/1/8
 */
public class TestYield {
    public static void main(String[] args) {
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<3;i++){
                    Thread.yield();
                    System.out.println(Thread.currentThread().getName());
                }
            }
        };
        new Thread(runnable,"Thread-A").start();
        new Thread(runnable,"Thread-B").start();
        new Thread(runnable,"Thread-C").start();
    }
}

对于线程让步我们尽量不要使用。
7.等待该线程终止join()方法
我们在一个线程里面如果调用了其他线程的join()方法,它就会阻塞当前线程,直到我们被调用的线程对象里面的run()方法执行完毕,这个线程才会继续执行。

package com.wschase.xianchengjianjie;

import sun.plugin2.message.Message;

/**
 * Author:WSChase
 * Created:2019/1/8
 */
public class TestJoin {
    //我们在一个线程里面如果调用了其他线程的join()方法,它就会阻塞当前线程,
    // 直到我们被调用的线程对象里面的run()方法执行完毕,这个线程才会继续执行。
    public static void main(String[] args) throws InterruptedException {
        //业务逻辑
        MyRunnable runnable=new MyRunnable();

        //线程
        Thread thread=new Thread(runnable,"Thread-A");
        thread.start();

        //在主线程中调用线程对象的join方法,会阻塞主线程
        //直到调用线程对象的run方法执行完毕,主线程才会继续执行
        thread.join();


        System.out.println("当前线程"+Thread.currentThread().getName());//main
    }

}
class MyRunnable implements Runnable{
    private int tick=100;
    @Override
    public void run() {
        while(this.tick>0){
            System.out.println(Thread.currentThread().getName()+"tick="+tick--);
        }
    }
}

作用:如果两个线程A、B的任务有相互依赖的关系,如果 B里面执行的内容依赖于A的结果,它的执行必须等到A执行完成以后才能执行,所以就可以使用我们的join()方法。
8.线程停止
在多线程中有三种方法可以停止线程
(1)设置标记为,线程正常退出
(2)使用stop方法强制退出,但是不安全,现在我们已经不使用这种方法了。
(3)使用Thread类中的一个interrupt()可以中断线程。

package com.wschase.thread2;

/**线程停止
 * Author:WSChase
 * Created:2019/1/9
 */
//    //1.通过标记位的方式让线程终止
//public class TestThread {
//    public static void main(String[] args) {
//
//        MyRunnable myRunnable=new MyRunnable();
//        Thread thread=new Thread(new MyRunnable(),"子线程");
//        thread.start();
//
//    //主线程休眠
//        try {
//            Thread.sleep(3000);
//
//            //1.修改标记为-->当我们的这个标记为等到3以后就会终止线程
//            myRunnable.setFlag(false);
//
//
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }
//}
//class MyRunnable implements Runnable{
//
//    private boolean flag=true;
//    @Override
//    public void run() {
//        int i=0;
//        while(this.flag){
//            System.out.println(Thread.currentThread().getName()+"循环执行第"+ ++i+"次");
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//    }
//
//    public void setFlag(boolean flag) {
//        this.flag = flag;
//    }
//}






//2.通过中断让线程停止
public class TestThread {
    public static void main(String[] args) {

        MyRunnable2 myRunnable2=new MyRunnable2();
        Thread thread=new Thread(new MyRunnable2(),"子线程");
        thread.start();

        //主线程休眠
        try {
            Thread.sleep(3000);
            //Thread的中断方法
            thread.interrupt();
            } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class MyRunnable2 implements Runnable{

    @Override
    public void run() {
        int i=0;
        while(true){
            System.out.println(Thread.currentThread().getName()+"循环执行第"+ ++i+"次");
            try {

                //判断线程的中断情况
                boolean interruptedStatus = Thread.currentThread().isInterrupted();
                //非阻塞情况
                if(interruptedStatus){
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("阻塞中断:"+Thread.currentThread().isInterrupted());
                return;
            }
        }
    }
}


在这里插入图片描述
对于中断方式终止线程:我们可以通过异常捕获在catch里面来决定是否要退出程序。
简而言之:当我们调用线程的interrupt方法的时候,它就会把我们中断的标记为改为true。
(1)那么如果是非阻塞情况,线程的中断由我们自己来决定,在程序里面通过异常捕获在catch里面来决定是否要退出程序。
(2)如果在阻塞情况下,阻塞又是由于我们的wait、sleep、join方法引起的,它会将我们的标记为改成一个false,然后再抛一个interruptException。
9.线程优先级
在我们的java中实际上我们的优先级是没有用的。所以在优先级这一块我们只需要直到两个点就可以啦:
(1)线程的优先级越高有可能先执行,并不是一定。
(2)优先级是可以继承的。

package com.wschase.thread2;

/**
 * Author:WSChase
 * Created:2019/1/9
 */
public class TestThreadyouxianji {
    public static void main(String[] args) {
    //主线程的优先级
        System.out.println("主线程的优先级:"+Thread.currentThread().getPriority());

        //在主线程中创建一个线程不指定优先级
        Thread threadA=new Thread(()->{
            System.out.println(Thread.currentThread().getName()
            +"优先级是:"+Thread.currentThread().getPriority());
        },"Thread-A");
        threadA.start();
        //当我们没有改变优先级的时候,这个Thread-A的优先级就是府县丞的优先级:5
        threadA.setPriority(6);
    }
}

对于优先级的继承:当我们在一个线程里面启动了另外一个线程,并且我们并没有给这个线程指定优先级,那么这个线程的有极限就是我们父线程的优先级。
10.守护线程
在java中我们一共有两种线程:
(1)用户线程
(2)守护线程:通过isDaemon()方法返回的如果是true,就是守护线程,返回false那么就不是守护线程。
守护线程是当我们的用户存在它就得一直工作,只有没有用户线程的时候,它才会同JVM一起停止工作,简言之守护线程就是守护用户线程的。

猜你喜欢

转载自blog.csdn.net/ZhuiZhuDream5/article/details/86084680