JAVA多线程
线程的创建的方式:
一:继承Thread类
由于JAVA里一个子类只能继承一个父类,所以继承Thread后的线程类无法拥有更多的功能,是最简单的创建线程的方法,学习阶段尝试线程感觉很方便
public class ThreadDemo1 {
public static void main(String[] args) {
//3.new一个新线程对象
Thread t = new MyThread();
//4.调用start方法启动线程(实际执行的还是run方法)
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("11111111111");
}
}
}
/**
1.定义一个线程类继承Thread类
*/
class MyThread extends Thread {
/**
2.重写run方法,里面是定义线程以后要干啥
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("============");
}
}
}
二:实现Runnable接口
定义Runnable接口的实现类,只是实现了接口,可以继续继承类和实现接口,扩展性强,Runnable的实现类创建的对象只是任务对象,需要交给Thread进行包装,Thread类才是真正的线程对象
public class ThreadDemo2 {
public static void main(String[] args) {
//3.创建一个任务对象
Runnable target = new MyRunnable();
//4.把任务对象交给Thread处理
Thread t = new Thread(target);
//5.启动线程
t.start();
//主线程随便写点东西
for (int i = 0; i < 10; i++) {
System.out.println("主线程执行输出:" + i);
}
}
}
/**
* 1.定义一个线程任务类,实现Runnable接口
*/
class MyRunnable implements Runnable {
/*
2.重写run方法,定义线程的执行的任务
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程执行输出:" + i);
}
}
}
//lambda表达式简化
/*
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程2执行输出:" + i);
}
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("子线程3执行输出:" + i);
}
}).start();
*/
三:实现Callable接口,用FutureTask创建新线程
将Callable的实现类包装到FutureTask里,再将FutureTask类作为任务对象包装到Thread类,可以调用FutureTask类的get()方法得到线程执行的返回值
(泛型里面是子线程执行结束后的返回值)
public class ThreadDemo3 {
public static void main(String[] args) {
//3.创建Callable 任务对象
Callable<String> call = new MyCallable(100);
//4.把Callable任务对象 交给FutureTask对象
//FutureTask对象的作用1:是Runnable的对象(实现了Runnable接口),可以交给Thread了
//FutureTask对象的作用2:可以在线程执行完毕之后通过调用其get方法得到线程执行完毕后的结果
FutureTask<String>f1 = new FutureTask<>(call);
//5.交给线程处理
Thread t1 = new Thread(f1);
//6.启动线程
t1.start();
Callable<String> call2 = new MyCallable(200);
FutureTask<String>f2 = new FutureTask<>(call2);
Thread t2 = new Thread(f2);
t2.start();
/**
get方法是FutureTask的方法
*/
try {
String rs = f1.get();
System.out.println("线程1"+rs);
} catch (Exception e) {
e.printStackTrace();
}
try {
String rs2 = f2.get();
System.out.println("线程2"+rs2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 1.定义一个任务类 实现Callable接口 应该声明线程任务执行完毕后的结果的数据类型
*/
class MyCallable implements Callable<String>{
private int n;
public MyCallable(int n) {
this.n = n;
}
public MyCallable() {
}
/*
重写call方法(任务方法)
*/
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 1; i <=n ; i++) {
sum+=i;
}
return "执行的结果是:"+sum;
}
}
利用线程池创建新线程
一:Runnable的实现类在线程池里用execute执行
public class ThreadPoolDemo1 {
public static void main(String[] args) {
/*
public ThreadPoolExecutor(int corePoolSize, 指定线程池的线程数量(核心线程)
int maximumPoolSize, 指定线程池可支持的最大线程数
long keepAliveTime, 指定临时线程的最大存活时间
TimeUnit unit, 指定存活世间的单位(秒、分、时、天)
BlockingQueue<Runnable> workQueue, 指定任务队列 workQueue
ThreadFactory threadFactory, 指定用哪个线程工厂创建线程 :threadFactory
RejectedExecutionHandler handler 指定线程忙,任务满的时候,新任务来了的处理方法)
*/
//1.创建线程池对象
ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());//丢弃任务并抛出异常(听说一般用这个)
//ThreadPoolExecutor.CallerRunsPolicy 由主线程负责调用任务的run方法从而绕过线程池直接执行
//ThreadPoolExecutor.DiscardPolicy 丢弃任务,但是不抛出异常
//ThreadPoolExecutor.DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入队列中
//2.给任务线程池处理
Runnable target = new MyRunnable();
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
}
}
二:Callable的实现类用submit执行
public class ThreadPoolDemo2 {
public static void main(String[] args) throws Exception {
/*
public ThreadPoolExecutor(int corePoolSize, 指定线程池的线程数量(核心线程)
int maximumPoolSize, 指定线程池可支持的最大线程数
long keepAliveTime, 指定临时线程的最大存活时间
TimeUnit unit, 指定存活世间的单位(秒、分、时、天)
BlockingQueue<Runnable> workQueue, 指定任务队列 workQueue
ThreadFactory threadFactory, 指定用哪个线程工厂创建线程 :threadFactory
RejectedExecutionHandler handler 指定线程忙,任务满的时候,新任务来了的处理方法)
*/
//1.创建线程池对象
ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());//丢弃任务并抛出异常(听说一般用这个)
//ThreadPoolExecutor.CallerRunsPolicy 由主线程负责调用任务的run方法从而绕过线程池直接执行
//ThreadPoolExecutor.DiscardPolicy 丢弃任务,但是不抛出异常
//ThreadPoolExecutor.DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入队列中
//2.给任务线程池处理
Future<String> f1 = pool.submit(new MyCallable(100));
Future<String> f2 = pool.submit(new MyCallable(200));
Future<String> f3 = pool.submit(new MyCallable(300));
Future<String> f4 = pool.submit(new MyCallable(400));
Future<String> f5 = pool.submit(new MyCallable(500));
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
System.out.println(f5.get());
}
}
三:使用Executors的工具方法直接得到一个线程池对象
public class ThreadPoolDemo3 {
public static void main(String[] args) {
//1.创建固定线程数据的线程池
//允许请求的任务队列长度是Integer.MAX_VALUE
ExecutorService pool = Executors.newFixedThreadPool(3);//创建固定线程数量的线程池,有线程异常,就补充一个新的
//ExecutorService pool = Executors.newSingleThreadExecutor();// z
//创建线程数量最大上限是Integer.MAX_VALUE
//ExecutorService pool = Executors.newCachedThreadPool();
//ExecutorService pool = Executors.newScheduledThreadPool();
pool.execute(new MyRunnable());
}
}
Executors的工具方法底层还是采用ThreadPoolExecutor方法创建线程池
线程安全
使用synchronized关键字给线程加锁,一般使用对应的对象作为锁
静态方法可以使用类名.class作为锁
线程通信
使用notify唤醒等待的线程
使用wait将当前线程休眠
public class Phone {
//实现线程间通信,默认认为手机当前处于等待来电提醒
private boolean flag = false;
public void run() {
//a.负责来电提醒的线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (Phone.this) {
if (!flag) {
//代表要来电话提醒了
try {
System.out.println("有新电话呼入,可以接听");
flag = true;
Thread.sleep(1000);
Phone.this.notify();
Phone.this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}).start();
//b.接电话线程,正式接听
new Thread(new Runnable() {
@Override
public void run() {
try {
//不断地接听电话
while (true) {
synchronized (Phone.this) {
if (flag) {
//可以接听电话了
System.out.println("电话已接通,这两人正在聊天");
Thread.sleep(1000);
flag = false;
//唤醒别人,等待自己
Phone.this.notify();
Phone.this.wait();
} else {
Phone.this.notify();
Phone.this.wait();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public static void main(String[] args) {
//1.创建一部手机对象
Phone phone = new Phone();
phone.run();
}
}