线程创建
- 继承Thread
/**
* 继承Thread 创建线程
*/
public class ThreadDemo1 {
public static void main(String[] args) {
//创建线程
Thread thread = new MyThread();
//启动线程
thread.start();
}
}
class MyThread extends Thread {
@Override
public void run() {
//具体的业务代码
Thread thread = Thread.currentThread();
System.out.println("线程名称 " + thread.getName());
}
}
继承Thread新建线程的缺点:因为java中有单继承特性,所以如果继承了Thread之后,就不能继承其他类。
- Thread的变种方式,使用匿名内部类
/**
* 继承Thread 使用匿名内部类
*/
public class ThreadDemo3 {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
//具体的业务代码
Thread t = Thread.currentThread();
System.out.println("线程名称 " + t.getName());
}
};
//启动线程
thread.start();
}
}
- 实现Runnable接口
/**
* 实现Runnable接口
*/
public class ThreadDemo2 {
public static void main(String[] args) {
//创建Runnable子对象
MyThread2 myThread = new MyThread2();
//创建线程
Thread thread = new Thread(myThread);
thread.start();
}
}
class MyThread2 implements Runnable{
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println("线程名称 " + thread.getName());
}
}
- 实现Runnable接口,使用匿名内部类 (Runnable的变种1)(常用创建方式)
/**
1. 实现Runnable接口,使用匿名内部类
*/
public class ThreadDemo4 {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println("线程名称 " + t.getName());
}
});
thread.start();
}
}
- 使用Lambda匿名Runnable方式(jdk8之后的版本,不需要返回值时,建议使用这种创建方法)
/**
* 使用 lambda 表达式
*/
public class ThreadDemo5 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
Thread t = Thread.currentThread();
System.out.println("线程名称 " + t.getName());
});
thread.start();
}
}
以上五种创建线程的方法有一个共同点,都没有返回值,即当主线程运行完成后没有新线程的执行结果。
- 带返回值的Callable
/**
* 带返回值的Callable
*/
public class ThreadDemo7 {
//实现Callable接口
public static class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//生成随机数0-19
int randomNum = new Random().nextInt(20);
System.out.println(Thread.currentThread().getName() + " 生成随机数:" + randomNum);
return randomNum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建Callable子对象
MyCallable myCallable = new MyCallable();
//使用FutureTask用于接收Callable结果的对象
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
//创建线程
Thread thread = new Thread(futureTask);
//启动线程
thread.start();
//得到线程执行的结果
int result = futureTask.get();
System.out.println(Thread.currentThread().getName() + " 中拿到新线程执行的结果为:" + result);
}
}
}
- 匿名Callable(常用创建方式)
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 匿名Callable
*/
public class ThreadDemo8 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() {
int[] arr = new int[]{1, 2, 3};
Integer result = arr[new Random().nextInt(2)];
System.out.println(Thread.currentThread().getName() + " 随机数组元素:" + result);
return result;
}
});
//创建新线程
Thread thread = new Thread(futureTask);
thread.start();
//FutureTask函数是用来接受返回值
Integer result = futureTask.get();
System.out.println(Thread.currentThread().getName() + " 中得到新线程的返回值:" + result);
}
}
线程的常见构造方法
-
Thread()
创建线程对象
-
Thread(Runnable target)
使用Runnable对象创建线程对象
-
Thread(Runnable target,String name)
使用Runnable对象创建线程对象,并命名
- Thread(String name) 创建线程对象,并命名
可以使用jconsole观察该线程是否创建:
- Thread(ThreadGroup group,Runnable target)
线程组,可以用来分组管理线程
package thread;
import java.util.Random;
/**
* 线程组
*/
public class ThreadDemo11 {
public static void main(String[] args) {
//创建分组
ThreadGroup group = new ThreadGroup("thread-group");
//设置公共的任务(线程的任务)
Runnable runTask = new Runnable() {
@Override
public void run() {
//生成一个跑步能几秒到达终点的任务
//随机生成数1-4
int num = (1 + new Random().nextInt(5));
try {
//sleep 的单位时毫秒
Thread.sleep(num * 1000);
System.out.println("选手到达终点:" + num + "s");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//创建线程
Thread t1 = new Thread(group, runTask);
Thread t2 = new Thread(group, runTask);
Thread t3 = new Thread(group, runTask);
//启动线程
t1.start();
t2.start();
t3.start();
//等到所有人都到达终点,宣布成绩
while (group.activeCount() != 0) {//activeCount 活跃线程数,所有人到达之后,才能宣布成绩
}
System.out.println("宣布成绩结果");
}
}
线程中断
常见的两种方式:
1.通过自定义标记符来进行终端
2.调用interrupt()方法来中断
/**
* 使用自定义标识符终止线程
*/
public class ThreadInterrupt1 {
private volatile static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!flag) {
System.out.println("正在转帐...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("差点被发现了!");
});
thread.start();
Thread.sleep(3000);
//终止线程
System.out.println("有内鬼终止交易");
flag = true;
}
}
/**
* 使用interrupt终止线程
*/
public class ThreadInterrupt2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
//判断方法(两种方法)
// while (!Thread.interrupted()) {
// System.out.println("正在转账...");
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// break;
// }
// }
while (!Thread.currentThread().isInterrupted()) {
System.out.println("正在转账...");
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// break;
// }
}
System.out.println("差点误了大事!");
System.out.println("终止标志位2:" +Thread.currentThread().isInterrupted());
// System.out.println("终止标志位4:" +Thread.interrupted());
});
thread.start();
Thread.sleep(1000);
//执行方法
thread.interrupt();
}
}
Thread.interrupted()和Thread.currentThread().isInterrupted()的区别
1.interrupted()属于静态方法,所有程序都可以直接调用的全局方法;而isInterrupted属于某个实例的方法
2.interrupted()在使用完后会重置终端标识符,而isInterrupted不会重置中断标识符
interrupted():
isInterrupted:
线程等待
import java.time.LocalDateTime;
/**
* join示例
* 第一种使用:直接使用线程.join() 意思是等待某种线程执行完成后再执行后续线程
* 第二种使用: 使用线程.join(时间) 意思是等待上一种线程执行最多多长时间后就执行后续线程,不会等到上一种线程执行完
* 等到某个线程执行完成后,在执行后续代码
* join不设置等待参数的情况下,是无限等待
* 优势(相比于isAlive):写法优雅,实行的是阻塞等待wait(),所运行的资源更少
*/
public class ThreadByJoin {
//执行的顺寻应该为1.3.1.3
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
//1.张三开始上班
System.out.println("1.张三开始上班!" + LocalDateTime.now());
//2.张三正在上班
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.张三下班
System.out.println("3.张三下班!" + LocalDateTime.now());
});
thread1.start();
// while (thread1.isAlive()) {
// }
thread1.join(500);
Thread thread2 = new Thread(() -> {
//1.李四开始上班!
System.out.println("1.李四开始上班!" + LocalDateTime.now());
//2.李四正在上班
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.李四下班!
System.out.println("3.李四下班!" + LocalDateTime.now());
});
thread2.start();
}
}
线程休眠
使用sleep休眠
Thread.sleep(3*1000);//单位是毫秒
使用TimeUnit休眠
TimeUnit.DAYS.sleep(1);//天
TimeUnit.HOURS.sleep(1);//小时
TimeUnit.MINUTES.sleep(3);//分钟
TimeUnit.SECONDS.sleep(3);//秒
TimeUnit.MILLISECONDS.sleep(1);//毫秒
TimeUnit.MICROSECONDS.sleep(1);//微秒
TimeUnit.NANOSECONDS.sleep(1);//纳秒
获取线程实例
package thread;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 实现多线程数组求和
*/
public class ThreadDemo6 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//记录开始执行的时间
long stime = System.currentTimeMillis();
int[] array = new int[10000000];
//随机数初始化
Random random = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = (1 + random.nextInt(100));
}
// 创建两个线程相加
// 计算偶数下标元素的和
FutureTask<Integer> task1 = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int temp = 0;
for (int i = 0; i < array.length; i = i + 2) {
temp += array[i];
}
System.out.println("线程1:" + temp);
return temp;
}
});
Thread t1 = new Thread(task1);
t1.start();
//计算奇数下标元素的和
FutureTask<Integer> task2 = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int temp = 0;
for (int i = 1; i < array.length; i = i + 2) {
temp += array[i];
}
System.out.println("线程2:" + temp);
return temp;
}
});
Thread t2 = new Thread(task2);
t2.start();
int sum = task1.get() + task2.get();
System.out.println("多线程数组总和:" + sum);
//执行完成结束时间
long etime = System.currentTimeMillis();
//执行时间
System.out.println("最终执行时间:" + (etime - stime));
}
}