一、多线程介绍
1、Java中创建线程的方法3种:Thread、Runnable、Callable
- 继承Thread类 (Thread类本身就是实现Runnable接口的)
- 实现Runnable接口
- 实现Callable接口
2、继承Thread类
①通过继承Thread类,重写run方法实现多线程
/**
* 通过继承Thread类,重写run方法实现多线程
*/
@Slf4j
public class TestThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 200; i++)
log.info("子线程输出:" + Thread.currentThread().getName() + "-" + i);
}
public static void main(String[] args) {
TestThread1 test1 = new TestThread1(); //新开第1个线程
test1.start(); //start方法启动线程
TestThread1 test2 = new TestThread1(); //新开第2个线程
test2.start(); //start方法启动线程
for (int i = 0; i < 200; i++) {
log.info("主线程输出:" + Thread.currentThread().getName() + "-" + i);
}
}
}
②通过匿名内部类,重写run方法实现多线程
/**
* 通过匿名内部类,重写run方法实现多线程
*/
@Slf4j
public class TestThread2 {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) {
//打印线程名,线程名是从0开始的
log.info("子线程输出:" + Thread.currentThread().getName() + "-" + i);
}
}
}
};
thread.start();
Thread thread1 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) {
//打印线程名,线程名是从0开始的
log.info("子线程输出:" + Thread.currentThread().getName() + "-" + i);
}
}
}
};
thread1.start();
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) {
//打印线程名,线程名是从0开始的
log.info("主线程输出:" + Thread.currentThread().getName() + "-" + i);
}
}
}
}
3、实现Runnable接口
/**
* 通过Runnable接口,重写run方法,实现多线程
*/
@Slf4j
public class TestThread3 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
log.info("子线程输出:" + Thread.currentThread().getName() + "-" + "看书++++++++");
}
}
public static void main(String[] args) {
//创建runnable接口的实现类对象
TestThread3 testThread3 = new TestThread3();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread1 = new Thread(testThread3); //新开第1个线程
thread1.start();
Thread thread2 = new Thread(testThread3); //新开第2个线程
thread2.start();
for (int i = 0; i < 200; i++) {
log.info("主线程输出:" + Thread.currentThread().getName() + "-" + "写字++++++++");
}
}
}
4、实现Callable接口
/**
* 通过Callable接口,重写call方法,实现多线程
*/
@Slf4j
public class TestThread4 implements Callable<Integer> {
@Override
public Integer call() {
int count = 0;
for (int i = 0; i < 200; i++) {
if (i % 2 == 0) {
count++;
log.info("子线程输出:" + Thread.currentThread().getName() + "-" + count);
}
}
return count;
}
public static void main(String[] args) throws Exception {
TestThread4 testThread4 = new TestThread4(); //新开1个线程
FutureTask<Integer> futureTask = new FutureTask<>(testThread4);
new Thread(futureTask).start(); //开启线程
for (int i = 0; i < 200; i++) {
log.info("主线程输出:" + Thread.currentThread().getName() + "-" + i);
}
log.info("主线程输出:" + Thread.currentThread().getName() + "-" + futureTask.get());
}
}
二、多线程和线程池的区别
- 线程池是在程序运行开始,创建好的n个线程,并且这n个线程挂起等待任务的到来;而多线程是在任务到来得时候进行创建,然后执行任务。
- 线程池中的线程执行完之后不会回收线程,会继续将线程放在等待队列中;多线程程序在每次任务完成之后会回收该线程。
- 由于线程池中线程是创建好的,所以在效率上相对于多线程会高很多。
- 线程池在高并发的情况下有着较好的性能,不容易挂掉;多线程在创建线程数较多的情况下,很容易挂掉。