多线程
多线程概述
一个进程之中可以有多个线程,每一个线程都会开辟一个不同的栈空间,在这个栈空间中,
同一个进程的不同线程共享资源。
认识线程
package thread;
public class ThreadTest01 {
//除去垃圾回收线程之外,只剩下一个主线程
public static void main(String[] args) {
}
}
实现线程的第一种方式
package thread;
/**
* 实现线程的第一种方式:
* 编写一个类,继承java.lang.thread。重写run方法
*/
public class ThreadTest02 {
public static void main(String[] args) {
//新建一个分支线程
MyThread myThread = new MyThread();
//启动线程,这个方法会在JVM中开辟一个新的栈空间,这段代码执行完之后瞬间结束
//启动成功会自动调用run方法,并且run方法在分支栈底部(压栈)
//run方法与main方法都在各自进程的底部。
myThread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程--->"+ i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("分支线程--->"+ i);
}
}
}
//输出结果
/**
*主线程--->0
*分支线程--->0
*分支线程--->1
*主线程--->1
*分支线程--->2
*主线程--->2
*两个线程在抢同一个时间片
*/
实现线程的第二种方式
package thread;
public class ThreadTest03 {
public static void main(String[] args) {
//采用匿名内部类的方式创建一个线程,更高级的写法可以使用lombok表达式
//编写一个类,实现java.lang.Runnable接口,实现run方法。
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程"+i);
}
}
});
t.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程"+i);
}
}
}
不使用匿名内部类的方式创建一个线程
package thread;
/**
*不使用匿名内部类的方式实现一个线程,实现接口Runnable
*传入所创建的线程中
*/
public class ThreadTest07 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
MyThread05 myThread05=new MyThread05();
Thread t = new Thread(myThread05);
}
}
class MyThread05 implements Runnable{
@Override
public void run() {
// TODO 自动生成的方法存根
}
}
实现线程的第三种方式
package thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
*实现线程的第三种方式
* 实现Callable接口
*/
public class ThreadTest10 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建一个“未来任务类”对象
FutureTask task= new FutureTask(new Callable() {
@Override
//此时线程可以执行一个任务,返回一个东西
public Object call() throws Exception {
return 300;
}
});
Thread t = new Thread(task);
t.start();
//在主线程中回去未来任务线程中的返回值
//get()方法的执行会导致“当前线程阻塞”
Object obj =task.get();
System.out.println(obj);
//main方法这里的程序想要执行必须等待get()方法的结束
//但是get()方法的执行可能需要很久
System.out.println("hello world");
}
}
返回当先线程名字
package thread;
/**
* 1:修改某一个线程名字
* t1.setName("t1线程")
* 2:获取线程名字
* t2.getName()
* 3:获取当前线程对象(这是一个静态方法,返回一个Thread类型的对象)
* Thread.currentThread()
*
*/
public class ThreadTest04 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Thread currentThread= Thread.currentThread();
System.out.println(currentThread.getName());
MyThread2 t1 = new MyThread2();
t1.setName("t1线程");//输出 t1线程
t1.start();
System.out.println(t1.getName());//Thread-0 默认线程名字
MyThread2 t2 = new MyThread2();
t2.setName("t2线程");//输出 t2线程
t2.start();
System.out.println(t2.getName());//Thread-1 默认线程名字
}
}
class MyThread2 extends Thread{
@Override
public void run() {
Thread currentThread= Thread.currentThread();
System.out.println(currentThread.getName());
}
}
使线程睡眠的sleep方法
package thread;
import java.util.Date;
/**
*1:静态方法:Thread.sleep(1000*5)
*2:参数是毫秒
*3:作用:让当前线程进入休眠,进入阻塞状态,放弃战友的cpu时间片,让给其他线程使用。
*
* 当睡眠的代码出现在哪个线程中,哪个线程就会进入休眠,直至时间结束
*/
public class ThreadTest05 {
public static void main(String[] args) throws InterruptedException {
MyTherd03 t = new MyTherd03();
Date date = new Date();
System.out.println(date); //Wed Oct 26 23:01:49 CST 2022
//因为出现在主线程中,所以使主线程睡眠5秒
t.sleep(1000*5);
Date date2 = new Date();
System.out.println(date2); //Wed Oct 26 23:01:54 CST 2022
}
}
class MyTherd03 extends Thread{
}
合理的终止一个线程
通过以下方式终止线程的优点:更加便于实际中使用,贴合现实。
package thread;
public class ThreadTest06 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
MyThread4 r= new MyThread4();
Thread t = new Thread(r);
t.setName("t");
t.start();
//模拟5秒
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
//通过一个布尔值控制一个线程的结束
r.run=false;
}
}
class MyThread4 implements Runnable{
boolean run =true;
@Override
public void run() {
// TODO 自动生成的方法存根
for (int i = 0; i < 10; i++) {
if (run) {
System.out.println(Thread.currentThread().getName()+"---->"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}else {
//在这里可以对进程终止前的数据进行一系列操作(保存等)
return;
}
}
}
}
线程优先级
package thread;
/**
*获取线程的优先级
*线程最高优先级为10
* 默认优先级为5
* 最低优先级为1
*可以通过静态方法获取当先线程
* 获取当先线程,并获得其优先级
* Thread.currentThread().getPriority()
* 修改当前线程的优先级
* Thread.currentThread().setPriority(1);
当一个线程的优先级低时,也会抢夺时间片,知识抢夺时间片的能力较低
*/
public class ThreadTest08 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Thread.currentThread().setPriority(1);
System.out.println(Thread.currentThread().getPriority());
}
}
线程让位
Thread.yield(); 这是一个静态方法
其在一瞬间做出让位到达就绪状态重新抢夺时间片
由官方文档可以得出:向调度程序提示当前线程愿意放弃其当前使用的处理器。
调度程序可以忽略此提示。
Yield是一种改进相对进展的启发式尝试否则会过度使用CPU。
其用途应结合详细的分析和基准测试确保它实际上具有期望的效果。
线程合并
package thread;
public class Threadtest09 {
public static void main(String[] args) {
System.out.println("main线程开始");
Thread t = new Thread(new MyRunnable01());
t.setName("t");
t.start();
//合并线程
try {
t.join(); //t合并到当前线程中,当前线程收到阻塞,直至t线程运行完毕,
//两个线程都没有消失,知识当前线程收到阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main线程结束");
}
}
class MyRunnable01 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000/2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}