欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

day20Java-常用对象Thread-多线程实现方式1继承Thread类

程序员文章站 2022-05-09 13:16:13
...
博客名称
Java-常用对象总结(高级)

多线程实现方式1继承Thread类

需求:实现多线程的程序。
如何实现多线程?
	由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。而进程是由系统创建的。所以我们应该去调用系统的功能创建一个进程。Java是不能直接调用系统功能的,所以,没有办法直接实现多线程程序。但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西,然后提供一些类供我们使用。这样我们就可以实现多线程程序了。

那么Java提供的类是什么呢?
	Thread
	通过查看API,我们知道了有两种方式实现多线程程序。

方式1:	继承Thread类
步骤:
	A:自定义类MyThread继承Thred类
	B:MyThread类里面重写run()方法?
			为什么是run()方法呢?
	C:创建对象
	D:启动线程

类要重写run()方法,为什么呢?
	不是类中的所有代码都需要被线程执行的,而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()
	用来包含那些被线程执行的代码。	

面试题:run()方法和start()方法的区别?
run():仅仅封装了被线程执行的代码,直接调用就是普通方法。
start():首先是启动了线程,再由jvm去调用该线程的run方法。

代码演示

public class MyThreadDemo {
    public static void main(String[] args) {
        //MyThread my = new MyThread();
        //从执行结果看出,是单线程执行的,run()方法直接调用和普通方法一样,所以看到的就是单线程效果。
        //my.run();
        //my.run();

        //想要看到多线程效果,就必须要说另一个方法start();
        //MyThread my = new MyThread();
        //my.start();
        //IllegalThreadStateException:非法的线程状态异常
        //为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
        //my.start();

        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();
        //启动两个线程
        my1.start();
        my2.start();
    }
}

自定义类继承Thread类

public class MyThread extends Thread{
    //run里面封装的是多线程执行的代码
    @Override
    public void run() {
        for (int x = 0; x <5 ; x++) {
            System.out.println(x);
        }
    }
}

结果:从结果看出,没有看见再抢cpu执行,是因为次数太少了,增加循环次数就行了。

0
1
2
3
4
0
1
2
3
4

获取线程对象的名称

public final String getName():获取线程的名称。
如何设置线程对象的名称呢?
public final void setName(String name):设置线程的名称(有兴趣可看看源码)

针对不是Thread类的子类中如何获取线程对象名称呢?
public static Thread currentThread():返回当前正在执行的线程对象
Thread.currentThread().getName()

代码演示

public class MyThreadDemo {
    public static void main(String[] args) {
        //无参构造+setXxx
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //设置线程名称
        my1.setName("格雷福斯");
        my2.setName("至高之拳");
        //启动线程
        my1.start();
        my2.start();

        //带参构造
        MyThread my3 = new MyThread("疾风剑豪");
        MyThread my4 = new MyThread("影流之主");

        //启动线程
        my3.start();
        my4.start();

        //如果我想获取main方法所在的线程对象名称该怎么办?
        //Thread提供了一个很好玩的静态方法
        //public static Thread currentThread():返回当前正在执行的线程对象
        System.out.println(Thread.currentThread().getName());
    }
}

自定义类继承Thread类

public class MyThread extends Thread {

    public MyThread() {
        super();
    }

    public MyThread(String name) {
        super(name);
    }
    //run里面封装的是多线程执行的代码
    @Override
    public void run() {
        for (int x = 0; x < 5; x++) {
            System.out.println(getName() + "----" + x);
        }
    }
}

结果:我启动了4个线程,还有一个是执行main方法的线程

main
影流之主----0
至高之拳----0
影流之主----1
至高之拳----1
影流之主----2
至高之拳----2
影流之主----3
至高之拳----3
影流之主----4
至高之拳----4
格雷福斯----0
格雷福斯----1
格雷福斯----2
格雷福斯----3
格雷福斯----4
疾风剑豪----0
疾风剑豪----1
疾风剑豪----2
疾风剑豪----3
疾风剑豪----4

线程调度

演示如何设置和获取线程优先级
那么,默认优先级是多少呢?

如何获取线程对象的优先级?
public final int getPriority():返回线程对象的优先级
如何设置线程对象的优先级呢?
public final void setPriority(int newPriority):更改线程的优先级。 (在线程启动之前)

注意:
  		线程默认优先级是5。
  		线程优先级的范围是:1-10。
  		线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。

public static final int MAX_PRIORITY 10 最高
public static final int MIN_PRIORITY 1  最低
public static final int NORM_PRIORITY 5 默认

代码演示

public class ThreadPriorityDemo {
    public static void main(String[] args) {

        ThreadPriority tp1  = new ThreadPriority();
        ThreadPriority tp2  = new ThreadPriority();
        ThreadPriority tp3  = new ThreadPriority();

        tp1.setName("奥拉夫");
        tp2.setName("挖掘机");
        tp3.setName("德邦总管");

		//public final int getPriority():返回线程对象的优先级
        //获取默认优先级
        //System.out.println(tp1.getPriority());//5
        //System.out.println(tp2.getPriority());//5
        //System.out.println(tp3.getPriority());//5

        //设置优先值
        //IllegalArgumentException:非法参数异常
        //tp1.setPriority(1000);

	    //public final void setPriority(int newPriority):更改线程的优先级。 (在线程启动之前)
        //通过查看API设置正确的优先级
        tp1.setPriority(1);
        tp3.setPriority(10);

        //启动线程
        tp1.start();
        tp2.start();
        tp3.start();
    }
}

自定义类继承Thread

public class ThreadPriority extends  Thread {
	//run里面封装的是多线程执行的代码
    @Override
    public void run() {
        for (int x = 0; x <10 ; x++) {
            System.out.println(getName()+"----"+x);
        }
    }
}

结果:

德邦总管----0
德邦总管----1
德邦总管----2
德邦总管----3
德邦总管----4
德邦总管----5
德邦总管----6
德邦总管----7
德邦总管----8
德邦总管----9
挖掘机----0
挖掘机----1
挖掘机----2
挖掘机----3
挖掘机----4
挖掘机----5
挖掘机----6
挖掘机----7
挖掘机----8
挖掘机----9
奥拉夫----0
奥拉夫----1
奥拉夫----2
奥拉夫----3
奥拉夫----4
奥拉夫----5
奥拉夫----6
奥拉夫----7
奥拉夫----8
奥拉夫----9

线程控制

已经知道了线程的调度,接下来就可以使用如下方法对象线程进行控制
public static void sleep(long millis):线程休眠
public final void join():等待该线程终止。(注意:要在线程启动后才调用 )
public static void yield():线程礼让(暂停当前正在执行的线程对象,并执行其他线程。)
public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。
public final void stop():中断线程
public void interrupt():中断线程

public static void sleep(long millis):线程休眠

代码演示

public class SleepThreadDemo {
    public static void main(String[] args) {
        SleepThread st1 = new SleepThread();
        SleepThread st2 = new SleepThread();
        SleepThread st3 = new SleepThread();

        //设置线程对象名称
        st1.setName("人马");
        st2.setName("诺克");
        st3.setName("蛮王");

        //启动线程
        st1.start();
        st2.start();
        st3.start();
    }
}

自定义类继承Thread类

public class SleepThread extends Thread {
    @Override
    public void run() {
        for (int x = 0; x <10 ; x++) {
            System.out.println(getName()+"----"+x);
            try {
            	//public static void sleep(long millis):线程休眠
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果:

蛮王----0
人马----0
诺克----0
蛮王----1
人马----1
诺克----1
蛮王----2
诺克----2
人马----2
蛮王----3
诺克----3
人马----3
蛮王----4
人马----4
诺克----4
蛮王----5
诺克----5
人马----5
蛮王----6
诺克----6
人马----6
蛮王----7
诺克----7
人马----7
蛮王----8
诺克----8
人马----8
蛮王----9
诺克----9
人马----9
public final void join():等待该线程终止。

该方法要启动后调用
代码演示

public class JoinThreadDemo {
    public static void main(String[] args) {

        JoinThread jt1 = new JoinThread();
        JoinThread jt2 = new JoinThread();
        JoinThread jt3 = new JoinThread();

        //设置线程对象名称
        jt1.setName("卢锡安");
        jt2.setName("复仇之矛");
        jt3.setName("皮城女警");

       //注意:等待该线程终止,要放在线程启动之后,不然看不出效果
        /*try {
            //public final void join():等待该线程终止。
            jt1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/

        //启动线程
        jt1.start();
        try {
            //public final void join():等待该线程终止。
            jt1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        jt2.start();
        jt3.start();
    }
}

自定义类继Thread类

public class JoinThread extends ThreadPriority{
    @Override
    public void run() {
        for (int x = 0; x <10 ; x++) {
            System.out.println(getName()+"-"+x);
        }
    }
}

结果:等待卢锡安线程执行完,才执行其他两个线程。

卢锡安-0
卢锡安-1
卢锡安-2
卢锡安-3
卢锡安-4
卢锡安-5
卢锡安-6
卢锡安-7
卢锡安-8
卢锡安-9
复仇之矛-0
复仇之矛-1
复仇之矛-2
复仇之矛-3
复仇之矛-4
复仇之矛-5
复仇之矛-6
复仇之矛-7
复仇之矛-8
复仇之矛-9
皮城女警-0
皮城女警-1
皮城女警-2
皮城女警-3
皮城女警-4
皮城女警-5
皮城女警-6
皮城女警-7
皮城女警-8
皮城女警-9
public static void yield():线程礼让(暂停当前正在执行的线程对象,并执行其他线程。)

让多个线程的执行更和谐,但是不能靠它保证一人一次。
代码演示

public class YieldThreadDemo {
    public static void main(String[] args) {
        YieldThread yt1 = new YieldThread();
        YieldThread yt2 = new YieldThread();

        //设置线程对象名称
        yt1.setName("疾风剑豪");
        yt2.setName("影流之主");

        //启动线程
        yt1.start();;
        yt2.start();;
    }
}

自定义类继承Thread类

public class YieldThread extends Thread {
    @Override
    public void run() {
        for (int x = 0; x <20 ; x++) {
            System.out.println(getName()+"-"+x);
            //public static void yield():线程礼让(暂停当前正在执行的线程对象,并执行其他线程。)
            Thread.yield();
        }
    }
}

结果:

疾风剑豪-0
影流之主-0
疾风剑豪-1
疾风剑豪-2
影流之主-1
疾风剑豪-3
影流之主-2
疾风剑豪-4
影流之主-3
疾风剑豪-5
影流之主-4
疾风剑豪-6
影流之主-5
疾风剑豪-7
影流之主-6
疾风剑豪-8
影流之主-7
疾风剑豪-9
影流之主-8
疾风剑豪-10
影流之主-9
疾风剑豪-11
影流之主-10
疾风剑豪-12
疾风剑豪-13
疾风剑豪-14
疾风剑豪-15
疾风剑豪-16
疾风剑豪-17
疾风剑豪-18
疾风剑豪-19
影流之主-11
影流之主-12
影流之主-13
影流之主-14
影流之主-15
影流之主-16
影流之主-17
影流之主-18
影流之主-19
public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。

当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。 守护线程不会立即停止,而是有一个缓冲过程。
举例:
坦克大战

代码演示

public class DaemonThreadDemo {
    public static void main(String[] args) {
        DaemonThread dt1= new DaemonThread();
        DaemonThread dt2= new DaemonThread();

        //设置线程对象名称
        dt1.setName("张飞");
        dt2.setName("关羽");

        //设置为守护线程
        dt1.setDaemon(true);
        dt2.setDaemon(true);

        //启动线程
        dt1.start();
        dt2.start();

        //设置当前线程对象名称
        Thread.currentThread().setName("刘备");
        for (int x = 0; x <5 ; x++) {
            System.out.println(Thread.currentThread().getName()+"-"+x);
        }
    }
}

自定义类继承Thread类

public class DaemonThread extends Thread {
    @Override
    public void run() {
        for (int x = 0; x <200 ; x++) {
            System.out.println(getName()+"-"+x);
        }
    }
}

结果:

刘备-0
刘备-1
刘备-2
刘备-3
刘备-4
关羽-0
张飞-0
关羽-1
张飞-1
关羽-2
张飞-2
关羽-3
关羽-4
张飞-3
关羽-5
张飞-4
关羽-6
张飞-5
关羽-7
关羽-8
关羽-9
关羽-10
关羽-11
public final void stop():中断线程

public final void stop():让线程停止,过时了,但是还可以使用。(该方法是有点暴力的不建议使用)

代码演示

public class StopThreadDemo {
    public static void main(String[] args) {
        StopThread st1 = new StopThread();

        //设置线程对象名称
        st1.setName("至高之拳");

        //启动线程
        st1.start();

        //停止线程
        try {
            Thread.sleep(3000);
            st1.stop();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

自定义类继承Thread类

public class StopThread extends Thread {
    @Override
    public void run() {
        for (int x = 0; x <20 ; x++) {
            System.out.println(getName()+"-"+x);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果:

至高之拳-0
public void interrupt():中断线程

public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。
当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出该异常。

public class InterruptThreadDemo {
    public static void main(String[] args) {
        InterruptThread it = new InterruptThread();
        //设置线程对象名称
        it.setName("法外狂徒");
        //启动线程
        it.start();
        try {
            Thread.sleep(3000);
            //停止线程
            //开始我这里是有一个疑问?
            //为什么这里终止了线程,是在自定义的线程类抛出的异常。
            //因为我在这里终止的程序,但是自定义线程类中,的Thread.sleep(10000)睡眠还未结束,我在这里就终止了程序,所以就抛出的异常
            //详细可以查看该异常的描述。
            it.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

自定义类继承Thread类

public class InterruptThread extends Thread {
    @Override
    public void run() {
        System.out.println("代码开始了");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                System.out.println("线程终止了");
                e.printStackTrace();
            }
        System.out.println("代码结束了");
    }
}

结果:

代码开始了
线程终止了
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at com.ginger.demo09.InterruptThread.run(InterruptThread.java:8)
代码结束了

线程的生命周期

新建:创建线程对象
就绪:有执行资格,没有执行权
运行:有执行资格,有执行权
			阻赛:由于一些操作然线程处于了该状态。没有执行资格,没有执行权。二另一些操作可以把它**,**后处于就绪状态。
死亡:线程对象变成垃圾,等待被回收。

线程的生命周期图解
day20Java-常用对象Thread-多线程实现方式1继承Thread类

相关标签: Java相关知识