目录
1. 多线程 VS 单线程性能
2. 线程3中创建方式
2.1 创建方式一:继承Thread(1种写法)
2.2 创建方式二:实现Runnable及变种(4种写法)
2.3 创建方式三:带返回值的Callable(2种写法)
线程休眠演示打印电影字幕:
public class App {
public static void main(String[] args) throws InterruptedException {
String content = "我要你知道,这个世界上有⼀个⼈会永远等着你。⽆论是在什么
时候,⽆论你在什么地⽅,反正你知道总会有这样⼀个⼈。";
for (char item : content.toCharArray()) {
System.out.print(item);
Thread.sleep(500);
}
} }
1. 多线程 VS 单线程性能
/**
* 单线程
*/
class SingleThread {
static final int maxCount = 10;
public static void main(String[] args) throws InterruptedException {
// 获得当前毫秒数(开始时间)
long stime = System.currentTimeMillis();
for (int i = 0; i < maxCount; i++) {
Thread.sleep(1000);
}
// 获得当前毫秒数(结束时间)
long etime = System.currentTimeMillis();
System.out.println("已经执⾏完:" + (etime - stime));
}
}
// 输出:已经执⾏完:10084
/**
* 多线程
*/
class MultiThread {
static final int maxCount = 10;
public static void main(String[] args) throws InterruptedException {
// 获得当前毫秒数(开始时间)
long stime = System.currentTimeMillis();
// 先创建⼀个新线程【注意:创建新线程不能放到底下】
Thread t2 = new Thread(() -> {
for (int i = 0; i < maxCount / 2; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t2.start();
for (int i = 0; i < maxCount / 2; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t2.join(); // 等待线程 2 执⾏完
// 获得当前毫秒数(结束时间)
long etime = System.currentTimeMillis();
System.out.println("已经执⾏完:" + (etime - stime));
}
}
//输出:已经执⾏完:5132
2. 线程3中创建方式
2.1 创建方式一:继承Thread(1种写法)
// 创建⽅式 1:继承 Thread
class MyThread extends Thread {
@Override
public void run() {
System.out.println("你好,线程");
Thread thread = Thread.currentThread();
System.out.println("线程的名称:" + thread.getName());
}
}
// 测试类
public class ThreadExample {
public static void main(String[] args) {
// 获得当前的线程
Thread mainThread = Thread.currentThread();
System.out.println("线程名称:" + mainThread.getName());
// 创建线程
Thread thread = new MyThread();
// 启动线程
thread.start();
}
}
//输出:
线程名称:main
你好,线程
线程名称 :Thread-0
继承Thread新建线程的缺点:Java语言是单继承,如果继承了Thread之后,就不能继承其他类。
启用线程用start() 还是run() ?
run方法和start方法区别:
1. 调用start方法是真正开启一个线程来执行任务,而调用run方法相当于执行普通方法run,并不会开启新线程。
2. run方法也叫做线程体,它里面包含了具体要执行的业务代码,当调用run方法时,会立即执行run方法中的代码(如果当前线程时间片未使用完);而调用start方法时,是启用一个线程并将线程的状态设置为就绪状态,也就是说调用start方法,并不会立即执行。
3. 因为run方法时普通方法,而普通方法是可以被多次调用的,所以run方法可以被多次调用;而start 方法是创建新线程来执行任务,因为线程只能被创建一次,所以第三个区别就是:run方法可以被调用多次,而start方法只能被调用一次。
2.2 创建方式二:实现Runnable及变种(4种写法)
public class ThreadDemo4 {
public static void main(String[] args) {
//创建Runnable 子对象
MyThread2 myThread2 = new MyThread2();
//创建线程
Thread thread = new Thread(myThread2);
//启动线程
thread.start();
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
//得到当前线程
Thread thread = Thread.currentThread();
System.out.println("你好,线程");
}
}
//输出:你好,线程
变种⽅法 1:匿名 Runnable ⽅式
public class ThreadDemo5 {
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();
}
}
//输出:执行任务Thread-0
变种⽅法 2:匿名⽅式创建⼦对象
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("任务执行:" + t.getName());
}
};
// 启动线程
t1.start();
//输出:任务执行:Thread-0
使⽤ Lambda 匿名 Runnable ⽅式
JDK 8 以上的版本创建线程,推荐使用此方式
public class ThreadDemo7 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
//具体业务
Thread t = Thread.currentThread();
System.out.println("任务执行:" + t.getName());
});
thread.start();;
}
}
//输出:任务执行:Thread-0
以上的线程创建方式有一个共同的问题:线程执行完成之后,主线程没有办法拿到新线程的执行结果,无返回值。
2.3 创建方式三:带返回值的Callable(2种写法)
带返回值的 Callable
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo8 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建Callable实例
MyCallable myCallable = new MyCallable();
//用于接受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<V> 泛型里面可以使任意数据类型
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//生成随机数 0 - 9
int randomNum = new Random().nextInt(10);
System.out.println(Thread.currentThread().getName() +
" ----随机数" + randomNum);
return randomNum;
}
}
// 输出: Thread-0 ----随机数8 main新线程的返回结果8
匿名 Callable
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo9 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
String[] arrs =new String[]{"Java","MySQL","Thread"};
String result = arrs[new Random().nextInt(3)];
System.out.println(Thread.currentThread().getName() +
"一字符串" + result);
return result;
}
});
//创建线程
Thread thread = new Thread(futureTask);
//启动线程
thread.start();
String result = futureTask.get();
System.out.println(Thread.currentThread().getName() +
"一新线程的返回值" + result);
}
}
// 输出: Thread-0一字符串MySQL main一新线程的返回值MySQL