仅作为Java多线程的复习梳理笔记,如果有错误希望大家批评指出
1.使用Java多线程
- 继承
Thread
类:
public class MyThread extends Thread{
@Override
public void run() {
// 重写run()方法,这个方法就是线程进入running状态后要运行的方法
super.run();
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
// 因为是继承自Thread类,所以可以直接创建线程对象
Thread t1 = new MyThread();
Thread t2 = new MyThread();
// 调用start()方法以后,该线程会进入ready状态
// 操作系统会进行调度,根据调度算法线程可能会进入running状态
// 只有线程真正进入running状态以后,CPU才会执行该线程的代码
t1.start();
t2.start();
}
}
打印输出结果:
Thread-1
Thread-0
直接继承自Thread
类是实现Java多线程最直接的一种方式,因为是继承自Thread
类,所以可以直接创建线程对象,线程运行时执行的代码或者方法需要放在重写父类的run()
方法里。
- 实现
Runnable
接口
如果当当前类已近有一个父类,这时候就不能再继承Thread
类,所以可以实现Runnable
接口来使用多线程。
public class MyThread implements Runnable{
@Override
public void run() {
// 实现Runnale类一定要重写run()方法
// 因为接口的方法是抽象方法,所以必须得实现
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
// 创建线程传入Runnale接口的实例
// 因为我们实现了Runnale接口,所以MyThread类的实例就是它的实例
// 后面的参数是此线程的线程名
Thread t1 = new Thread(new MyThread(),"线程1");
Thread t2 = new Thread(new MyThread(),"线程2");
t1.start();
t2.start();
}
}
打印结果:
线程1
线程2
2.常用方法
public static void main(String[] args) {
System.out.println(Thread.currentThread());
System.out.println(Thread.currentThread().getPriority());
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getId());
System.out.println(Thread.currentThread().isAlive());
}
输出:
Thread[main,5,main]
5
main
1
true
Thread.currentThread()
:获取当前正在运行的线程的指针Thread.getPriority()
:获取该线程的优先级Thread.getName())
:获取线程的名字Thread.getId()
:获取该线程在JVM中的IDThread.isAlive()
:获取该线程的存活状态,只要是调用了start()方法以后,无论是该线程处在ready状态还是running状态,该线程都是存活状态。
3.线程休眠
public class MyThread implements Runnable{
@Override
public void run() {
// 分别打印:线程名,休眠开始前系统时间,休眠结束后系统时间
System.out.println(Thread.currentThread().getName());
System.out.println(System.currentTimeMillis());
try {
// 调用Thread.sleep(millis),使当前线程休眠1000毫秒
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(System.currentTimeMillis());
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyThread(),"线程1");
Thread t2 = new Thread(new MyThread(),"线程2");
t1.start();
// 调用join()方法以后,其他线程会等待该线程死亡以后再继续运行
// 其他线程包括主线程,都会处于等待状态(原理是使用了同步锁)
t1.join();
t2.start();
}
}
打印结果:
线程1
1523976884092
1523976885092
线程2
1523976885093
1523976886094
可以看到调用Thread.sleep()
方法以后,当前线程就进入一种休眠状态,也就是说这个线程会什么也不做的读过这段时间,要注意的是,该线程并不会释放同步锁。
4.优先级
在操作系统中,线程可以划分优先级,优先级越高的线程的到的CPU资源越多,设置线程优先级有助于操作系统决定下一次选择哪一个线程来优先执行(但是操作系统调度线程和优先级具有随机性)
public class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyThread(),"线程1");
Thread t2 = new Thread(new MyThread(),"线程2");
// 优先级划分等级从1-10
// 不在这个范围之内会抛出异常
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
打印结果:
线程2
线程1
当然也有可能打印结果:
线程1
线程2
因为:
- 线程优先级和代码执行顺序无关,但往往优先级高的线程完成同样的任务,结束时间要高于优先级低的线程(因为CPU资源分配更多)
- 优先级不代表优先执行该线程,而只是操作系统会尽量给予更多地CPU运算能力。
5.总结
- Java线程的本质:在JDK1.2以前,Java曾经使用自己的
Green Thread
实现了用户级别的线程(ULP),但是由于用户级别的线程存在种种问题(比如线程阻塞时和进程就会出现不一致问题),JDK1.2以后,JVM选择了交给操作系统进行线程管理(通过系统调用),也就是操作系统中常说的轻量级进程(LWP)。对于Windows系统,明确的划分了进程和线程两种数据结构,进行了较好的多线程实现,对于Linux系统,依旧是使用了进程的方式实现了线程。 - Java线程模型和操作系统线程的关系:参考我的另一篇文章–Java线程和操作系统线程的关系