线程的创建与使用详解
并发:在一段时间内完成任务的量{并发量}
并行:在同一时刻能完成任务的量【并行量】
高并发:上千 万 十万 百万 千万
进程:正在运行的程序 没有先后顺序执行是随机的 线程中cpu时间片分配是随机的
线程: 存在于进程中用来真正执行任务的(计算机运行最小单元)
在线程中CPU的时间片分配是随机的,也就导致了线程的执行是随机的
Java中只有Thread才是线程类,其他的都不是
创建线程:
java有一个专用的线程类Thread【唯一的线程类】
创建方式一: 一个类继承线程类 Thread
重写. run();方法【此线程运行的方法体】
通过 new Thread来创建方法
Thread thread = Thread.currentThread(); // 获取到当前线程对象
System.out.println(thread.getName()); // 获取当前线程的名字
创建线程的方式一 :
类 extends Thread 重写run()方法
- 应用领域 : 批量产生线程
- 缺陷 : 单继承缺陷(只能继承一个类,以后扩展不方便)
package demo1;
/**
* Java中有一个专用的线程类 : Thread 【唯一的线程类】
* 创建线程的方式一 : 类 extends Thread
* 重写run()方法
* 应用领域 : 批量产生线程
* 缺陷 : 单继承缺陷(只能继承一个类,以后扩展不方便)
*/
public class MyThread extends Thread { // MyThread 线程的子类
@Override
public void run() { // 此线程运行的方法体
for(;;) {
System.out.print(getName()+":"); // 获取当前线程的名字
System.out.print("欢");
System.out.print("迎");
System.out.print("光");
System.out.println("临");
}
}
}
主函数是主线程,
、Thread.currentThread(); // 获取到当前线程对象
.getName(); // 获取当前线程的名字
Thread.currentThread().getName(); // 获取到当前线程对象的线程名字
.start(); // 启动线程【只有线程才能启动】
.run(); // 普通面向对象的方法调用,并没有开辟一个真实的线程
通过new Thread来创建线程对象
package demo1;
public class Test {
public static void main(String[] args) { // 主函数(主线程)
// Thread thread = Thread.currentThread(); // 获取到当前线程对象
// System.out.println(thread.getName()); // 获取当前线程的名字
for (int i = 1; i <=10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
// 通过Thread来创建线程对象
MyThread thread = new MyThread();
thread.start(); // 启动线程【只有线程才能启动】
// thread.run(); // 普通面向对象的方法调用,并没有开辟一个真实的线程
for (;;) {
System.out.println("AAAAA");
}
}
}
通过Thread使用匿名内部类来创建出线程对象
语法:
Thread XXX = new Thread(){
重写run方法代码块{
}
};
XXX.start(); // 线程启动
package demo1;
public class Test2 {
public static void main(String[] args) {
// 通过Thread使用匿名内部类来创建出线程对象
Thread t1= new Thread() {
@Override
public void run() {
for (int i =1; i<=1000;i++) {
System.out.println(Thread.currentThread().getName()+": 划船不靠浆"+i);
}
}
};
t1.start(); // 线程启动
Thread t2= new Thread() {
@Override
public void run() {
for (int i =1; i<=2000;i++) {
System.out.println(Thread.currentThread().getName()+": 全靠浪"+i);
}
}
};
// 在线程中CPU的时间片分配是随机的,也就导致了线程的执行是随机的
t2.start(); // 线程启动
}
}
线程创建的第二种方式 :
## 类 implements Runnable
*** 重写run()方法**
*** 优点 : 解决了Thread单继承的缺陷问题,但是使用上变麻烦了一点
Runnable 中只有一个run()
public void run() {
}**
run()特点 : 没有返回值,不能抛出异常
引发思考 : 若线程执行后有返回值怎么处理? 使用线程的第三种创建方式来解决此问题
package demo2;
/**
* 线程创建的第二种方式 : 类 implements Runnable
* 重写run()方法
* 优点 : 解决了Thread单继承的缺陷问题,但是使用上变麻烦了一点
*/
public class MyRunnable implements Runnable{
@Override
public void run() {
for (;;) {
System.out.println(Thread.currentThread().getName()+":将进酒,杯莫停");
}
}
/**
* Runnable 中只有一个run()
* public void run() {
* }
* run()特点 : 没有返回值,不能抛出异常
* 引发思考 : 若线程执行后有返回值怎么处理? 使用线程的第三种创建方式来解决此问题
*/
}
创建一个Runnable接口类型的对象
Runnable target = new MyRunnable(); // 只是线程运行的一个规范(执行的内容)
package demo2;
public class Test {
public static void main(String[] args) {
// 创建一个Runnable接口类型的对象
Runnable target = new MyRunnable(); // 只是线程运行的一个规范(执行的内容)
// Java中只有Thread才是线程类,其他的都不是
// Thread t1 = new Thread(, "测试线程");
// t1.setName("测试线程");
// t1.start(); // 启动一个线程
// 阻塞 : 程序是按照一定的顺序执行
// 非阻塞:各自的程序都是独立运行的
for (;;) {
System.out.println(Thread.currentThread().getName()+":AAAAAAAA");
}
}
}
创建的方式
**
## 主流 :采用匿名内部类形式来创建Runnable对象 企业使用的方式 lambda
**
package demo2;
public class Test2 {
public static void main(String[] args) {
new Thread(() -> { // 企业使用的方式 lambda
for(;;) {
System.out.println(Thread.currentThread().getName()+":CCCCC");
}
}, "小明").start();
}
private static void demo3() {
// 主流 :采用匿名内部类形式来创建Runnable对象
Thread thread = new Thread(() -> { // 企业使用的方式 lambda
for(;;) {
System.out.println(Thread.currentThread().getName()+":CCCCC");
}
});
thread.setName("小张");
thread.start();
}
private static void demo2() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for(;;) {
System.out.println(Thread.currentThread().getName()+":BBBBB");
}
}
});
thread.start();
}
private static void demo1() {
//1. 采用匿名内部类形式来创建Runnable接口对象
Runnable target = new Runnable() {
@Override
public void run() {
for(;;) {
System.out.println(Thread.currentThread().getName()+":AAAAAA");
}
}
};
Thread thread = new Thread(target);
thread.start();
}
}
线程创建的第三种方式 :
处理线程执行后有结果返回的场景
语法 : 类 implements Callable
为什么 Callable 是一个泛型接口,泛型就是将来线程执行之后的返回结果类型
package demo3;
import java.util.concurrent.Callable;
/**
* 线程创建的第三种方式 : 处理线程执行后有结果返回的场景
* 语法 : 类 implements Callable<V>
* 为什么 Callable<V> 是一个泛型接口,泛型就是将来线程执行之后的返回结果类型
*
*/
public class MyCallable implements Callable<String>{
@Override
public String call() throws Exception { // 线程执行的核心方法,和run作用类似
StringBuilder builder = new StringBuilder();
for (int j = 0;j < 100;j++) {
for (char i = 'a'; i <= 'z'; i++) {
builder.append(i);
}
for (char i = 'A'; i <= 'Z'; i++) {
builder.append(i);
}
}
return builder.toString();
}
}
用法:
// 创建Callable接口类型的对象
Callable (范型)callable = new MyCallable();
// 创建一个FutureTask来接收callable执行的任务(只是用来接收线程执行后的结果的)
FutureTask futureTask = new FutureTask(callable);
// 通过查看源码知道 : FutureTask是Runnable的子类
// 能否通过Thread来创建出这个线程呢?
Thread thread = new Thread(futureTask);
thread.start(); // 启动线程
// 要从FutureTask中来接收线程执行的结果**
package demo3;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) {
// 创建Callable接口类型的对象
Callable<String> callable = new MyCallable();
// 创建一个FutureTask来接收callable执行的任务(只是用来接收线程执行后的结果的)
FutureTask<String> futureTask = new FutureTask<String>(callable);
// 通过查看源码知道 : FutureTask是Runnable的子类
// 能否通过Thread来创建出这个线程呢?
Thread thread = new Thread(futureTask);
thread.start(); // 启动线程
// 要从FutureTask中来接收线程执行的结果
try {
String result = futureTask.get(); // 一直等待线程执行结果的出现
System.out.println("结果长度:"+result.length());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
**
使用lambda表达式来创建callable对象
**
面试 :
run(),start() 有什么区别?
答 : run() 对象的一个普通方法,start()启动一个线程
Runnable与Callable的区别?
Runnable接口中只有run(),它没有返回值, 不能抛出异常
Callable<T>泛型接口只有call(). 有执行的返回值,能抛出异常**
package demo3;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test2 {
public static void main(String[] args) {
// 使用lambda表达式来创建callable对象
Callable<Integer> callable = () -> {
int sum = 0;
for (int i = 1; i <100; i+=2) {
sum += i*i;
}
return sum;
};
FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
new Thread(futureTask).start();
try {
Integer result = futureTask.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
/**
面试 :
run(),start() 有什么区别?
答 : run() 对象的一个普通方法,start()启动一个线程
Runnable与Callable的区别?
Runnable接口中只有run(),它没有返回值, 不能抛出异常
Callable<T>泛型接口只有call(). 有执行的返回值,能抛出异常
*/
}