[Java][华为云Java编程创造营][学习笔记][第三阶段][05_Java多线程实战][01_创建线程]

网友投稿 450 2022-05-30

1,创建线程

1.1,进程和线程

进程

进程是并发执行程序在执行过程中资源分配和管理的基本单元。

进程可以理解为一个应用程序的执行过程,应用程序一旦执行,就是一个进程。

线程

线程是进程的一个执行单元,是进程内可调度实体。

线程是比进程更小的独立运行的基本单位。

线程也被称为轻量级进程。

通俗理解进程和线程:

1,启动QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开了一个线程,传输语音开了一个线程。

2,通俗说:进程是爹妈,管着众多的线程子女。

进程和线程的区别

1.2,创建线程的五种方式

1,继承Thread类

通过继承Thread并且重写其run(),run方法中定义需要执行的任务。创建后的子类通过调用start()方法即可执行线程方法。

通过继承Thread实现的线程类,多个线程间无法共享线程类的实例变量。需要创建不同Thread对象,自然不共享资源。

class UserThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running " + i); } } } public class Demo1 { public static void main(String[] args) { for (int i = 0; i < 2; i++) { new UserThread().start(); } /* * Thread-1 is running 0 Thread-1 is running 1 Thread-1 is running 2 Thread-1 is running 3 Thread-1 is running 4 Thread-0 is running 0 Thread-0 is running 1 Thread-0 is running 2 Thread-0 is running 3 Thread-0 is running 4 * */ } }

2,实现Runnable接口

需要先定义一个类实现Runnable接口并重写该接口的run()方法,此run方法是线程执行体。

接着创建Runnable实现类的对象,作为创建Thread兑现个参数target,此Thread对象才是真正的线程对象。

利用实现Runnable接口的线程类创建对象,可以实现线程之间的资源共享。

class UserRunn implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running " + i); } } } public class Demo2 { public static void main(String[] args) { UserRunn runn = new UserRunn(); new Thread(runn).start(); new Thread(runn).start(); /* * 输出结果 * Thread-0 is running 0 Thread-0 is running 1 Thread-0 is running 2 Thread-0 is running 3 Thread-0 is running 4 Thread-1 is running 0 Thread-1 is running 1 Thread-1 is running 2 Thread-1 is running 3 Thread-1 is running 4 * */ } }

,3,实现Callable接口

实现Callable接口实现带有返回值的线程

Callable接口如同Runnable接口的升级版,其提供的call()方法将作为线程的执行体,同时允许有返回值。

Callable对象不能直接作为Thread对象的target,因为Callable接口是Java5新增的接口,不是Runnable接口的子接口。

对于这个问题的解决方案,就引入Future接口,此接口可以接受call()的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,可以作为Thread对象的target。

import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; class UserCallable implements Callable { @Override public Object call() throws Exception { return "hello"; } } public class Demo3 { public static void main(String[] args) throws ExecutionException, InterruptedException { UserCallable userCallable = new UserCallable(); FutureTask futureTask = new FutureTask(userCallable); Thread t = new Thread(futureTask); t.start(); System.out.println(futureTask.get());//hello } }

,4,继承TimerTask

Timer和TimerTask可以作为实现线程的另一种方式。

Timer是一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask。

TimerTask是一个抽象类,实现了Runnable接口,所以具备了多线程能力。

import java.util.Date; import java.util.Timer; import java.util.TimerTask; class UserTask extends TimerTask { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running " + new Date()); } } public class Demo4 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new UserTask(), 2000, 3000); /* * 输出结果 * Timer-0 is running Wed Dec 08 15:46:39 CST 2021 Timer-0 is running Wed Dec 08 15:46:42 CST 2021 Timer-0 is running Wed Dec 08 15:46:45 CST 2021 Timer-0 is running Wed Dec 08 15:46:48 CST 2021 Timer-0 is running Wed Dec 08 15:46:51 CST 2021 Timer-0 is running Wed Dec 08 15:46:54 CST 2021 Timer-0 is running Wed Dec 08 15:46:57 CST 2021 Timer-0 is running Wed Dec 08 15:47:00 CST 2021 Timer-0 is running Wed Dec 08 15:47:03 CST 2021 Timer-0 is running Wed Dec 08 15:47:06 CST 2021 Timer-0 is running Wed Dec 08 15:47:09 CST 2021 Timer-0 is running Wed Dec 08 15:47:12 CST 2021 Timer-0 is running Wed Dec 08 15:47:15 CST 2021 Timer-0 is running Wed Dec 08 15:47:18 CST 2021 * */ } }

5,通过线程池启动多线程

通过Executors的工具类可以创建线程池。

提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行。

降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗。

方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成CPU过度切换。

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo5 { public static void main(String[] args) { ExecutorService ex = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { ex.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } } }); } ex.shutdown(); /* * 输出结果 * pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-2 7 pool-1-thread-2 8 pool-1-thread-2 9 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-2 7 pool-1-thread-2 8 pool-1-thread-2 9 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-2 7 pool-1-thread-2 8 pool-1-thread-2 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-3 0 pool-1-thread-3 1 pool-1-thread-3 2 pool-1-thread-3 3 pool-1-thread-3 4 pool-1-thread-3 5 pool-1-thread-3 6 pool-1-thread-3 7 pool-1-thread-3 8 pool-1-thread-3 9 * */ } }

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo6 { public static void main(String[] args) { ExecutorService ex = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { ex.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } } }); } ex.shutdown(); /* * 输出结果 * pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 * */ } }

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo7 { public static void main(String[] args) { ExecutorService ex = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { ex.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } } }); } ex.shutdown(); /* * 输出结果 * pool-1-thread-1 0 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-4 0 pool-1-thread-4 1 pool-1-thread-4 2 pool-1-thread-4 3 pool-1-thread-4 4 pool-1-thread-4 5 pool-1-thread-4 6 pool-1-thread-4 7 pool-1-thread-4 8 pool-1-thread-4 9 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-3 0 pool-1-thread-5 0 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-5 1 pool-1-thread-3 1 pool-1-thread-3 2 pool-1-thread-3 3 pool-1-thread-5 2 pool-1-thread-5 3 pool-1-thread-5 4 pool-1-thread-5 5 pool-1-thread-5 6 pool-1-thread-5 7 pool-1-thread-5 8 pool-1-thread-5 9 pool-1-thread-2 7 pool-1-thread-3 4 pool-1-thread-3 5 pool-1-thread-3 6 pool-1-thread-3 7 pool-1-thread-3 8 pool-1-thread-3 9 pool-1-thread-2 8 pool-1-thread-2 9 * */ } }

[Java][华为云Java编程创造营][学习笔记][第三阶段][05_Java多线程实战][01_创建线程]

import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Demo8 { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + ",执行 " + new Date()); } }, 1, 3, TimeUnit.SECONDS); /* * 输出结果: * pool-1-thread-1,执行 Tue Dec 14 11:35:55 CST 2021 pool-1-thread-1,执行 Tue Dec 14 11:35:58 CST 2021 pool-1-thread-2,执行 Tue Dec 14 11:36:01 CST 2021 pool-1-thread-1,执行 Tue Dec 14 11:36:04 CST 2021 pool-1-thread-3,执行 Tue Dec 14 11:36:07 CST 2021 pool-1-thread-3,执行 Tue Dec 14 11:36:10 CST 2021 pool-1-thread-4,执行 Tue Dec 14 11:36:13 CST 2021 pool-1-thread-4,执行 Tue Dec 14 11:36:16 CST 2021 * */ } }

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo9 { public static void main(String[] args) throws InterruptedException { System.out.println("---start---"); ExecutorService executorService = Executors.newWorkStealingPool(); for (int i = 0; i < 10; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } Thread.sleep(3000);//让主线程等待子线程执行完毕,也可以使用计数器方式 System.out.println("---end---"); /* * 输出结果 * ---start--- ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ---end--- * */ } }

1.3,Thread类和Runnable接口区别

继承Thread类实现卖票操作

class MyThread extends Thread { private int ticket = 10; private String name; public MyThread(String name) { this.name = name; } public void run() { for (int i = 0; i < 500; i++) { if (this.ticket > 0) { System.out.println(this.name + "卖出第" + (10 - this.ticket-- + 1) + "票"); } } } } public class Demo10 { public static void main(String[] args) { MyThread mt1 = new MyThread("一号窗口"); MyThread mt2 = new MyThread("二号窗口"); MyThread mt3 = new MyThread("三号窗口"); mt1.start(); mt2.start(); mt3.start(); } /* * 输出结果 * 一号窗口卖出第1票 三号窗口卖出第1票 三号窗口卖出第2票 三号窗口卖出第3票 三号窗口卖出第4票 三号窗口卖出第5票 三号窗口卖出第6票 三号窗口卖出第7票 三号窗口卖出第8票 三号窗口卖出第9票 三号窗口卖出第10票 二号窗口卖出第1票 二号窗口卖出第2票 二号窗口卖出第3票 一号窗口卖出第2票 二号窗口卖出第4票 二号窗口卖出第5票 二号窗口卖出第6票 二号窗口卖出第7票 二号窗口卖出第8票 二号窗口卖出第9票 二号窗口卖出第10票 一号窗口卖出第3票 一号窗口卖出第4票 一号窗口卖出第5票 一号窗口卖出第6票 一号窗口卖出第7票 一号窗口卖出第8票 一号窗口卖出第9票 一号窗口卖出第10票 * */ }

实现Runnable接口实现卖票操作

class MyThread implements Runnable { private int ticket = 10; @Override public void run() { for (int i = 0; i < 500; i++) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖出第" + (10 - this.ticket-- + 1) + "票"); } } } } public class Demo11 { public static void main(String[] args) { MyThread mt = new MyThread(); Thread t1 = new Thread(mt, "一号窗口"); Thread t2 = new Thread(mt, "二号窗口"); Thread t3 = new Thread(mt, "三号窗口"); t1.start(); t2.start(); t3.start(); } } /* * 输出结果 * 一号窗口卖出第1票 一号窗口卖出第4票 一号窗口卖出第5票 一号窗口卖出第6票 一号窗口卖出第7票 一号窗口卖出第8票 一号窗口卖出第9票 一号窗口卖出第10票 三号窗口卖出第3票 二号窗口卖出第2票 * */

1.4,线程start和run方法的区别

线程对象调用run方法案例

class UserThread extends Thread { public void run() { System.out.println(Thread.currentThread().getName() + ",执行run方法"); } } public class Demo12 { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + ",执行main方法"); UserThread userThread = new UserThread(); userThread.run(); /* * 输出结果 * main,执行main方法 main,执行run方法 * */ } }

线程对象使用start()方法案例

class UserThread extends Thread { public void run() { System.out.println(Thread.currentThread().getName() + ",执行run方法"); } } public class Demo13 { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + ",执行main方法"); UserThread userThread = new UserThread(); userThread.start(); /* * 输出结果 * main,执行main方法 Thread-0,执行run方法 * */ } }

1.5,线程的优先级

Java线程的优先级范围是1-10,默认优先级是5,10最高。

线程的优先级仍然无法保障线程的执行次序。

优先级高的线程获取CPU资源的概率较大,优先级低的并非没机会执行。

主线程main的优先级是5.

Java线程的优先级案例

class UserThread extends Thread { public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "第" + i + "次执行!"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class UserRunn implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + ",第" + i + "次执行!"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Demo14 { public static void main(String[] args) { Thread t1 = new UserThread(); Thread t2 = new Thread(new UserRunn()); //t1.setPriority(10); t2.setPriority(1); t2.start(); //t1.start(); /* * t1执行结果 * Thread-0第0次执行! Thread-0第1次执行! Thread-0第2次执行! Thread-0第3次执行! Thread-0第4次执行! Thread-0第5次执行! Thread-0第6次执行! Thread-0第7次执行! Thread-0第8次执行! Thread-0第9次执行! * */ /* * t2执行结果 * Thread-1,第0次执行! Thread-1,第1次执行! Thread-1,第2次执行! Thread-1,第3次执行! Thread-1,第4次执行! Thread-1,第5次执行! Thread-1,第6次执行! Thread-1,第7次执行! Thread-1,第8次执行! Thread-1,第9次执行! * */ } }

1.6,定时线程的任务调度

定时线程Schedule():延时不追加执行任务

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; class UserTask extends TimerTask { @Override public void run() { System.out.println(Thread.currentThread().getName() + "," + new Date()); } } public class Demo15 { public static void main(String[] args) { Timer t = new Timer(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date date = null; try { date = sdf.parse("2021-12-14 00:00:00"); } catch (ParseException e) { e.printStackTrace(); } t.schedule(new UserTask(), date, 3 * 60 * 1000); /* * 输出结果 * Timer-0,Tue Dec 14 21:48:23 CST 2021 * */ } }

定时线程scheduleAtFixedRate():延时追加执行任务

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; class UserTask extends TimerTask { @Override public void run() { System.out.println(Thread.currentThread().getName() + "," + new Date()); } } public class Demo16 { public static void main(String[] args) { Timer t = new Timer(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date date = null; try { date = sdf.parse("2021-12-14 05:00:00"); } catch (ParseException e) { e.printStackTrace(); } t.scheduleAtFixedRate(new UserTask(), date, 3 * 60 * 1000); /* * 输出结果 * Timer-0,Tue Dec 14 21:40:32 CST 2021 Timer-0,Tue Dec 14 21:40:32 CST 2021 * */ } }

1.7,接口同步回调和异步回调

同步调用

一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用。

回调

一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。

异步调用

一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方。

接口同步回调案例

interface Callback { public void process(int status); } class MyCallback implements Callback { @Override public void process(int status) { System.out.println("处理成功,返回状态为:" + status); } } class Server { public void getMsg(Callback callback, String msg) throws InterruptedException { System.out.println("服务端获得消息:" + msg); //模拟处理消息过程,等待两秒 Thread.sleep(2000); System.out.println("服务端处理成功,返回状态为200"); //处理完消息,调用回调方法,告知客户端 callback.process(200); } } class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(final String msg) { System.out.println("客户端正在发送消息:" + msg); try { server.getMsg(new MyCallback(), msg); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("客户端已经发送消息给服务器了,请稍等"); } } /* * 接口同步回调案例 * */ public class Demo17 { public static void main(String[] args) { Server server = new Server(); Client client = new Client(server); client.sendMsg("我要充值"); /* * 输出结果 * 客户端正在发送消息:我要充值 服务端获得消息:我要充值 服务端处理成功,返回状态为200 处理成功,返回状态为:200 客户端已经发送消息给服务器了,请稍等 * */ } }

接口异步调用案例

interface Callback { public void process(int status); } class MyCallback implements Callback { @Override public void process(int status) { System.out.println("处理成功,返回状态为:" + status); } } class Server { public void getMsg(Callback callback, String msg) throws InterruptedException { System.out.println("服务端获得消息:" + msg); //模拟处理消息过程,等待两秒 Thread.sleep(2000); System.out.println("服务端处理成功,返回状态为200"); //处理完消息,调用回调方法,告知客户端 callback.process(200); } } class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(final String msg) { System.out.println("客户端正在发送消息:" + msg); new Thread(new Runnable() { @Override public void run() { try { //调用server类的获取消息方法,并且传入mycallback对象 server.getMsg(new MyCallback(), msg); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); System.out.println("客户端已经发送消息给服务器了,请稍等"); } } public class Demo18 { public static void main(String[] args) { Server server = new Server(); Client client = new Client(server); client.sendMsg("我要充值"); /* * 输出结果 * 客户端正在发送消息:我要充值 客户端已经发送消息给服务器了,请稍等 服务端获得消息:我要充值 服务端处理成功,返回状态为200 处理成功,返回状态为:200 * */ } }

回调分为同步和异步,区别就是需不需要等待服务器端的返回结果

Java 多线程

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:德国大保险公司(化名)的巨型LeSS转型尝试(下)
下一篇:4G&5G;学习过程中整理的专业名词的符号简称
相关文章