引入线程
线程并行执行
package MyThread;
import java.util.Random;
/**
* @autor hh
* @date 2022/06/16 19:10
*/
public class ThreadTestDemo {
private static class MyThread extends Thread{
Random random = new Random();
@Override
public void run() {
while(true){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//main方法为主进程
//创建3个子线程
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
MyThread thread3 = new MyThread();
thread1.run();
thread2.run();
thread3.run();
Random random = new Random();
//主进程
while (true){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程的执行方式
问题:如果上锁后,那多线程不就变成单线程了吗?
我们只是在两个线程修改同一变量的时候, 才会加锁,如果有其他线程只是读取这个变量,那是没有影响的.
如果我们顺序执行每个线程,会不会打印main方法呢?
答案:不会,要等3个线程全部执行完才会打印主方法.
这里为什么打印的一直是main?
而不是thread0
,thread1
,thread2
,因为这块他们并不是线程,只是普通的调用run()方法而已,因为他们的主进程是main,这就是一直打印main的原因.
jconsole
在IDEA终端中使用jconsole命令可以查看当前程序线程的情况
线程创建的四种方式
继承Thread类
覆写run方法(线程的核心工作任务方法)
package innerClass;
/**
* 创建线程方式1
* @autor hh
* @date 2022/06/16 23:05
*/
public class ThreadMethod extends Thread{
@Override
public void run() {
System.out.println("我是一个子线程");
}
public static void main(String[] args) {
//创建线程类对象
ThreadMethod thread = new ThreadMethod();
//启动线程
thread.start();
//子线程输出语句
System.out.println("子线程输出语句");
}
}
我是实现Runnable接口,产生的线程
实现Runnable接口
覆写run方法
package innerClass;
/**
* 创建线程方式2
* 实现Runnable接口,覆写run方法
*
* @autor hh
* @date 2022/06/16 23:09
*/
public class ThreadMethod2 implements Runnable {
@Override
public void run() {
System.out.println("我是实现Runnable接口,产生的线程");
}
public static void main(String[] args) {
//创建线程任务对象
ThreadMethod2 thread2 = new ThreadMethod2();
//创建线程
Thread thread = new Thread(thread2);
//启动线程
thread.start();
}
}
覆写Callable接口,覆写call方法
使用线程池创建线程
import java.util.concurrent.*;
/**
* @autor hh
* @date 2022/07/14 15:29
* 实现Callable接口 -> 带返回值的接口, 覆写call()方法
* 接收call方法的返回值使用FutureTask对象
* Thread类,接收Callable接口必须通过FutureTask类的对象
* get()方法会阻塞当前线程,等待call()方法执行结束,才恢复执行
*/
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
};
// 接收call方法的返回值使用FutureTask对象
FutureTask<Integer> futureTask = new FutureTask<>(callable);
/**
// Thread类,接收Callable接口必须通过FutureTask类的对象
Thread thread = new Thread(futureTask);
thread.start();
// get()方法会阻塞当前线程,等待call()方法执行结束,才恢复执行
**/
// 使用线程池来执行
ExecutorService pool = Executors.newFixedThreadPool(3);
Future<Integer> callResult = pool.submit(callable);
int result = callResult.get();
System.out.println("子线程执行结束" + "result = " + result);
}
}
前两种方式启动线程都是通过Thread类的start来启动
推荐使用线程2,
使用Runnable更加灵活,子类还能实现其他的接口,继承别的类
方式1和方式2的另外3种写法
使用匿名内部类继承Thread类
public class ThreadMethod1 {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("匿名内部类继承了Thread类");
System.out.println(Thread.currentThread().getName(