1.线程使⽤
1.1 线程休眠演示打印电影字幕
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.2 多线程和单线程性能比较
/**
* 单线程
*/
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));
}
}
/**
* 多线程
*/
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));
}
}
使用多线程优点:整个程序的的执行效率大大提高了。
1.3 线程 三种创建⽅式
1.继承 Thread 进行实现(1种写法)
/**
* 继承Thread 创建线程
*/
public class ThreadDemo3 {
public static void main(String[] args) {
//获得当前的线程
Thread mainThread = Thread.currentThread();
System.out.println("线程名称:" + mainThread.getName());
Thread thread = new MyThread();
//开启线程
thread.start();
}
}
class MyThread extends Thread{
@Override
public void run(){
//具体的业务执行代码
Thread thread = Thread.currentThread();
try{
Thread.sleep(60 * 60 *1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("线程的名称:" + thread.getName());
}
}
a) 使⽤ jconsole 观察线程
![](https://i-blog.csdnimg.cn/blog_migrate/815cb654f72e33c577aa3d94bbb2d494.png)
因为 Java 是单继承,继承了 Thread 就不能继承其他类了,然⽽ Java 可以实现多个接⼝,于是有了另⼀种⽅式。
b) 启动线程——start ⽅法
通过覆写 run ⽅法创建⼀个线程对象,但线程对象被创建出来并不意味 着线程就开始运⾏了。
●
覆写 run ⽅法是提供给线程要做的事情的指令清单。
●
线程对象可以认为是把 李四、王五叫过来了。
●
⽽调⽤ start() ⽅法,就是喊⼀声:”⾏动起来!“,线程才真正独⽴去执⾏了。
RUN方法和START方法的区别
(1) 执行run方法:就是使用main线程调用一个普通方法而已
![](https://i-blog.csdnimg.cn/blog_migrate/d037407bef064611a1a7b248e6c71d38.png)
(2)执行start方法:新创建线程执行
注意:调⽤ start ⽅法, 才真的在操作系统的底层创建出⼀个线程。
2.实现Runnable 接口进行实现(4种写法)
a).
/**
*
* 实现Runnable 接口新建线程
*/
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{
public void run(){
//具体的业务代码
Thread thread = Thread.currentThread(); //得到当前线程
System.out.println("线程执行:" + thread.getName());
}
}
b). 匿名 Runnable ⽅式
/**
* 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();
}
}
c). 使⽤ Lambda 匿名 Runnable ⽅式: JDK8以上的版本建议使用
/**
* 使用lambda 来创建Runnable
*/
public class ThreadDemo6 {
public static void main(String[] args) {
Thread thread = new Thread(()->{
//具体的业务
Thread t = Thread.currentThread();
System.out.println("任务执行:" + t.getName());
});
//启动线程
thread.start();
}
}
d).
//创建线程并初始化
Thread thread = new Thread(){
@Override
public void run(){
Thread t = Thread.currentThread();
System.out.println("任务执行:" + t.getName());
}
};
thread.start();
注意:上述五种创建线程的方式都有一个共同点,没有返回值。及就是当线程执行完之后,主线程不能拿到新线程的执行结果。
3.实现Callable 接口进行实现(2种写法)
注意:要和future搭配使用
a)
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 {
//创建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("新线程返回的结果为:" + 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;
}
}
b)
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[]{"完美","乐观","幽默"};
//随即返回一个字符串
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);
}
}
总结:
创建线程有
3
⼤类实现⽅式、
7
种实现⽅法。
如果是 JDK
1
.
8
以上版本,在不需要获得线程执⾏结果的情况下,可以使⽤ Lambda ⽅式来创建线程,代码简洁;如果想要获取线程执⾏结果,可使⽤ FutureTask + Callable 的⽅式来实现。