day20Java-常用对象Thread-多线程实现方式1继承Thread类
博客名称 |
---|
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)
代码结束了
线程的生命周期
新建:创建线程对象
就绪:有执行资格,没有执行权
运行:有执行资格,有执行权
阻赛:由于一些操作然线程处于了该状态。没有执行资格,没有执行权。二另一些操作可以把它**,**后处于就绪状态。
死亡:线程对象变成垃圾,等待被回收。
线程的生命周期图解
下一篇: Hive表的导出与导入