🌞Java多线程
创建多线程
1. 继承Thread类
将类声明为Thread类的子类,并重写run方法,创建对象,开启线程
public class MyThread extends Thread{
@Override
public void run(){
synchronized (object) {
i++;
System.out.println("i:"+i);
try {
System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
i++;
System.out.println("i:"+i);
}
}
}
start():启动线程,sleep():在指定的毫秒数内让正在执行的线程休眠
当执行start()之后,jvm就会开启一个新的线程并且调用run方法,当执行线程的任务结束时,线程在内存中就会释放,当所有的线程都结束时,进程就会结束。
获取相应的线程名字mythread.currentThread().getName()
* currentThread():返回对当前正在执行的线程对象的引用
* getName():获取该线程的名字
2. 通过实现Runnable接口
实现Runable的好处:避免了单一继承的局限性,线程分为两部分,一部分是线程对象,另一部分是线程任务,继承Thread类,线程对象和线程任务耦合在一起,一旦创建了Thread类的子类,即是线程对象,又是线程任务,实现Runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型,Runnable接口对线程对象和线程任务进行解耦。
- 实现Runnable接口,并重写run方法
//1.实现runnable接口并重写run方法
class MyRunnable implements Runnable{
@Override
public void run() {
}
}
- 创建Runnable实例
MyRunnable runnable = new MyRunnable();
- 创建Thread对象
Thread thread = new Thread(runnable);
thread.start();
- 匿名的方法实现Runnable接口
//1.匿名实现Runnable接口并重写run方法
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
线程池
1. 创建线程池
线程池就是一个存在多个线程的容器,其中的线程可以重复使用,省去了重复创建线程浪费的操作,节省了资源。
- Runnable接口方法
通常,线程池都是由线程池工厂方法创建,再调用线程池中的方法获取线程。再通过线程去执行任务方法
Executors:线程池创建工厂类
public static ExecutorService newFixedThreadPool(int nThread):返回线程池对象
ExecutorService:线程池类
Future接口:用来记录线程任务执行完毕后产生的后果
使用线程池的方法:
- 创建线程池对象
- 创建Runnable接口子类对象
- 提交Runnable接口子类对象
- 关闭线程池
//创建线程池对象
ExecutorService service = Executor.newFixedThreadPool(2);
MyRunnable r = new MyRunnable();
//从线程池中获取对象,调用run方法
service.submit(r);
//关闭线程池
service.shutdown();
- Callable接口
Callable接口和Runnable接口相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可以抛出异常。
//创建线程池对象
ExecutorService service = Exectors.newFixedThreadPool(2);
MyCallable call = new MyCallable();
service.submit(call)
//创建Callable子类
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
System.out.println("我要一个教练:call");
Thread.sleep(2000);
System.out.println("教练来了: " +Thread.currentThread().getName());
System.out.println("教我游泳,交完后,教练回到了游泳池");
return null;
}
}
2. 等待子线程结束
有时候我们的主线程需要等子线程执行结束之后再开始执行。
- 第一种解决方法是使用全局标记
public class MyCallable implements Callable<Integer> {
public static int number=20;//总任务数
//...
}
number随便放那个类,只要static就好,
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建线程池对象
while(MyCallable.number!=0){
Thread.sleep(1000);
System.out.print("等待子线程执行...\n");
}
//执行结束
while循环放在主线程中,阻塞主线程,等number减为0的时候循环结束。
- 还有一种方法是使用插件CountDownLatch,不过没有试过,差不多也是这个原理,有阻塞主线程的功能。
线程池传参
使用的线程池是Executors,很简单,就是重写了构造方法,里面的参数在传入时尽量使用new方法重新创建,因为很可能会在第一个子线程传入参数还没有执行call的时候传参对象被第二个线程覆盖。
public class MyCallable implements Callable<Integer> {
public static int number=20;//总任务数
private int i = 0;//传入参数
public MyCallable(int i){
this.i = i;
}
@Override
public Integer call() throws Exception {
}
}
附Demo
Demo.java
package com.Runable;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
public static int number=20;//总任务数
private int i = 0;//传入参数
public MyCallable(int i){
this.i = i;
}
@Override
public Integer call() throws Exception {
System.out.print("线程"+i+"!\n");
Thread.sleep(3000);
//System.out.print(i);
System.out.print("线程"+i+"执行完毕!\n");
MyCallable.number--;
return (i%2==0?i:null);
}
}
MyCallable.java
package com.Runable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class Demo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
List<Integer> list = new ArrayList<>();
for (int i = 0; i <10; i++) {
list.add(i);
}
//创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(10);
List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
for (int i=0;i<list.size();i++){
MyCallable myCallable = new MyCallable(list.get(i));
futures.add(service.submit(myCallable));
}
while(MyCallable.number!=0){
Thread.sleep(1000);
System.out.print("...\n");
}
//执行结束
for (Future<Integer> i:futures){
System.out.print("获取结果"+i.get());
}
//关闭线程池
service.shutdown();
}
}
本文来自博客园,作者:两小无猜,转载请注明原文链接:https://www.cnblogs.com/charlottepl/p/13253157.html