多线程基础(二)
如何实现多线程程序?
由于线程是依赖进程而存在的,所以应该先创建一个进程出来。而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。但是,java可以去调用c/c++写好的程序来实现多线程程序。由c/c++去调用系统功能创建进程,然后由java去调用这样的东西,然后提供一些类供我们使用。我们就可以实现多线程程序了。
有两种方式可以实现多线程程序
方式1:继承Thread类。
方式2:实现Runnable接口。方式2实现请点击链接。https://www.jianshu.com/p/0dcd56c71231
一、Thread类
步骤
- 自定义类MyThread继承Thread类。
- MyThread类里面重写run()?
问题:为什么是run()方法呢?
答:不是类中的所有代码都需要被线程执行的,而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含哪些被线程执行的代码。 - 创建对象
- 启动线程
二、多线程的代码实现、获取和设置线程名称的办法
1 定义MyThread类、重写run()方法
public class MyThread extends Thread {
public MyThread() {}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "---" + i);
}
}
}
- 给线程起名字有两种办法:
1、无参构造和有参构造
2、setName&getName - 如何获取main方法所在的线程对象的名称:
public static Thread currentThread():返回当前正在执行的线程对象
System.out.println(Thread.currentThread().getName());
2 创建对象
public class MyThreadDemo01 {
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
my1.start();
my2.start();
}
}
面试题:run()和start()的区别?
run():仅仅是封装被线程执行的代码,直接调用是普通方法
start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
三、线程调度
public final int getPriority():返回线程对象的优先级
public final void setPriority(int newPriority):更改线程的优先级
注意:
线程默认优先级是5
线程优先级的范围是1-10
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。
public class MyThreadDemo03 {
public static void main(String[] args) {
ThreadPriority tp1 = new ThreadPriority();
ThreadPriority tp2 = new ThreadPriority();
ThreadPriority tp3 = new ThreadPriority();
tp1.setName("one");
tp2.setName("two");
tp3.setName("three");
tp1.setPriority(10);
tp2.setPriority(1);
tp3.setPriority(5);
tp1.start();
tp2.start();
tp3.start();
}
}
四、线程控制
1 休眠线程
public class ThreadSleep extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "---" + i + ",日期:" + new Date());
// 睡眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
- public static void sleep(long millis)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作收到系统统计时器和调度程序精度和准确性的影响。
2 加入线程
public final void join():等待该线程终止。
public class ThreadJoinDemo01 {
public static void main(String[] args) {
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.setName("1");
tj2.setName("2");
tj3.setName("3");
tj1.start();
try {
tj1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
}
}
效果:等待tj1线程结束后,tj2和tj3才能开始抢占CPU资源。
3 礼让线程
public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
在一定程度上让多个线程的执行更和谐,但是不能保证多个线程,一人一次。
public class ThreadYield extends Thread{
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(getName() + "---" + i);
Thread.yield();
}
}
}
效果:理想状态下,线程的执行是你一次我一次,但实际只能在一定程度上有效,并不能完全保证。
4 守护线程
- public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程、
- 当正在运行的线程都是守护线程时,Java虚拟机退出。该方法必须在启动线程前调用。
public static void main(String[] args) {
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
td1.setName("1");
td2.setName("2");
//设置守护线程
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
Thread.currentThread().setName("000");
for(int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "---" + ":" + i);
}
}
效果:如果被守护的线程执行完毕,守护线程即刻退出。
5 中断线程
public void interrupt():中断线程。把线程的状态终止,并抛出一个InterruptedException.
public class ThreadStop extends Thread{
@Override
public void run() {
System.out.println("开始执行:" + new Date());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("线程被中断了");
}
System.out.println("结束执行:" + new Date());
}
}
public static void main(String[] args) {
ThreadStop ts = new ThreadStop();
ts.start();
try {
Thread.sleep(3000);
ts.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}