java多线程的学习之路(一)
一、线程的生命周期
生命周期:
在程序开发中,将一个对象从被实例化完成,到这个对象使用结束,并销毁,将这样的过程称为对象的生命周期。类似于人的一生。
线程的生命周期: .
一个线程被实例化完成,到这个线程销毁,中间的过程。
线程的状态:
- 新生态: New
一个线程对象被实例化完成,但是还没有做任何的操作。 - 就绪态: Ready
一个线程已经被开启,已经开始争抢CPU时间片。 - 运行态: Run
一个线程抢到了CPU时间片,开始执行这个线程中的逻辑。 - 阻塞态: Interrupt
一个线程在运行的过程中,受到某些操作的影响,放弃了已经获取到的CPU时间片,并且不再参与CPU时间片的争
抢,此时线程处于挂起状态。 - 死亡态: Dead
一个线程对象需要被销毁。
线程状态之间的转换关系:
二、线程的实例化
第一种方式:继承Thread类
public class ThreadCreate {
public static void main(String[] args) {
//线程实例化
/* 1.继承Thread类, 做一个线程子类(自定义的线程类)*/
MyThread mt = new MyThread();
//注意:
//需要调用start方法,使线程启动。
// start方法会开启一个新的线程,来执行run中的逻辑
//如果直接调用run方法,则线程mt不会进入就绪态
mt.start();
System.out.println("主线程逻辑结束了");
}
}
//自定义的线程子类
class MyThread extends Thread{
/*
* 重写run方法
* 将需要并发执行的任务写到run方法中
*/
@Override
public void run() {
for(int i = 1;i <= 5;i++)
System.out.println("子线程中的逻辑:"+ i);
}
}
输出结果:
主线程逻辑结束了
子线程中的逻辑:1
子线程中的逻辑:2
子线程中的逻辑:3
子线程中的逻辑:4
子线程中的逻辑:5
第二种方式:实现Runnable接口
public class ThreadCreate {
public static void main(String[] args) {
//匿名方法
Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 1; i<=5; i++)
System.out.println("子线程1中的逻辑:"+ i);
}
};
//lambda表达式
Runnable r1 = ()->{
for (int i = 1; i<=5; i++)
System.out.println("子线程2中的逻辑:"+ i);
};
Thread t = new Thread(r); t.start();
Thread t1 = new Thread(r1); t1.start();
System.out.println("主线程逻辑结束了");
}
}
输出结果:
主线程逻辑结束了
子线程2中的逻辑:1
子线程2中的逻辑:2
子线程2中的逻辑:3
子线程2中的逻辑:4
子线程1中的逻辑:1
子线程2中的逻辑:5
子线程1中的逻辑:2
子线程1中的逻辑:3
子线程1中的逻辑:4
子线程1中的逻辑:5
因为Java是单继承的,更多使用实现Runnable接口的方法。
三、线程的命名
public class ThreadMethod {
public static void main(String[] args) {
//线程的命名
//1.set方法
Thread t = new Thread();
t.setName("custom");
System.out.println(t.getName());
//2.构造方法
//new Thread(Runnable r, String name)
Thread t1 = new Thread(()->{},"custom2");
System.out.println(t1.getName());
}
}
四、线程的休眠
public class ThreadMethod {
public static void main(String[] args) {
MyThread2 myThread2 = new MyThread2();
myThread2.start();
}
}
//自定义的线程子类
class MyThread2 extends Thread{
/*
* 重写run方法
* 将需要并发执行的任务写到run方法中
*/
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:每隔一秒输出一个数字。
五、线程的优先级
设置线程的优先级,只是修改这个线程可以去抢到CPU时间片的概率
public class ThreadMethod {
public static void main(String[] args) {
threadPriority();
}
/*
* 设置线程的优先级
*/
private static void threadPriority() {
//设置线程的优先级,只是修改这个线程可以去抢到CPU时间片的概率。
//并不是优先级高的线程一定能抢到CPU时间片
//优先级的设置,是一个整数,[0, 10]的整数,默认是5
Runnable r1 = ()->{
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r1);
//设置优先级必须放到start之前
t1.setPriority(7);
t1.start();
t2.start();
}
}
如果不设置优先级,两个线程的默认优先级为5:
Thread-0 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-0 3
Thread-1 3
Thread-0 4
Thread-1 4
设置了线程0的优先级为7以后,线程0强夺到CPU的概率更大:
Thread-0 0
Thread-1 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
六、线程的礼让
public class ThreadMethod {
public static void main(String[] args) {
threadYield();
}
/*线程的礼让..*/
private static void threadYield(){
//当前线程从 run->ready,释放CPU资源
Runnable r1 = ()->{
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==3)
Thread.yield();
}
};
Thread t1 = new Thread(r1,"Thread-1");
Thread t2 = new Thread(r1,"Thread-2");
t1.start();
t2.start();
}
}
当线程1的i = 3时,线程1礼让,线程0强夺到CPU
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-2 0
Thread-1 4
Thread-2 1
Thread-1 5
Thread-2 2
Thread-1 6
Thread-2 3
Thread-1 7
Thread-2 4
Thread-2 5
Thread-2 6
Thread-1 8
Thread-2 7
Thread-1 9
Thread-2 8
Thread-2 9