文章目录
一、多线程的创建和使用
1、方式一:继承Thread的类
1.1 创建一个继承Thread的类;
1.2 重写Thread中run()方法;
1.3 创建Thread类的子类对象;
1.4 通过此对象调用start()方法
1.5 例子1:遍历100以内的偶数
package Thread;
/**
* @author Muluo
* @create 2021-01-17 19:37
* 例子:遍历100以内的偶数
*/
public class ThreadTest {
public static void main(String[] args) {
// 1.3 创建Thread类的子类对象;
MyThread myThread = new MyThread();
// 通过此对象调用start()方法
myThread.start();
// 如下操作是在main线程中操作的
for (int i = 0; i < 1000; i++) {
if (i % 2 != 0) {
System.out.println("*****************main***************");
}
}
}
}
// 1.1 创建一个继承Thread的类;
class MyThread extends Thread {
@Override
// 1.2 重写Thread中run()方法;①:启动当前线程 ②:调用当前线程的run()方法
public void run() {
for (int i = 0; i < 1000; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
}
}
1.6 例子2:一个线程遍历100以内的奇数,一个线程遍历一百以内的偶数
package Thread;
/**
* 案例:一个线程遍历100以内的奇数,一个线程遍历一百以内的偶数
* @author Muluo
* @create 2021-01-17 20:24
*/
public class ExerThread {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
MyThread2 myThread2 = new MyThread2();
myThread1.start();
myThread2.start();
}
}
class MyThread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
1.7 创建Thread类的匿名子类的方式
package Thread;
/**
* 案例:一个线程遍历100以内的奇数,一个线程遍历一百以内的偶数
* @author Muluo
* @create 2021-01-17 20:24
*/
public class ExerThread {
public static void main(String[] args) {
// 创建Thread类的匿名子类的方式
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}.start();
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}.start();
}
}
注意:
问题一:
调用myThread.run()方法 是单线程的 不是多线程的,
问题二:
在启动一个线程,遍历一百以内的偶数, 不可以让已经start的线程去执行,错误:java.lang.IllegalThreadStateException
2、方式二:实现Runnable接口
1、创建一个实现Runnable接口的类
2、实现类去实现Runnable中的抽象方法;run()
3、创建实现类的对象
4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5、通过Thread类的对象在调用start()方法
package Thread;
/**
* 多线程的创建:
* 方式二: 实现Runnable接口
* 1、创建一个实现Runnable接口的类
* 2、实现类去实现Runnable中的抽象方法;run()
* 3、创建实现类的对象
* 4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
* 5、通过Thread类的对象在调用start()方法
* @author Muluo
* @create 2021-01-18 19:43
*/
// 1、创建一个实现Runnable接口的类
class MThread implements Runnable{
// 2、实现类去实现Runnable中的抽象方法;run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
public class RunnableExe {
public static void main(String[] args) {
// 3、创建实现类的对象
MThread mThread = new MThread();
// 4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread thread1 = new Thread(mThread);
thread1.setName("线程一");
// 5、通过Thread类的对象在调用start()方法
thread1.start();
// 在启动一个线程遍历100以内的偶数
Thread thread2 = new Thread(mThread);
thread2.setName("线程二");
thread2.start();
}
}
`3、继承Thread类和Runnable接口实现多线程的比较
开发中,优先选择实现Runnable接口的方式;
原因:实现的方式没有类的单继承性的局限性,实现的方式,更适合处理多个线程共享数据的情况
联系:Thread类本身也是实现于Runnable接口的
相同点:都要重写run()方法,将线程要执行的逻辑声明在run()方法中
如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大
call()可以返回值的
。call()可以抛出异常,被外面的操作捕获,获取异常的信息
Callable是支持泛型的
4、方式三:实现Callable接口(JDK5.0新增)
- 创建一个Callable接口的实现类
- 实现call方法,将此线程需要执行的操作声明在call()方法中
- 需要创建Callable接口实现类的对象
- 将此Callable接口的实现类的对象传递到FutureTask构造器中,创建futureTask的对象
- 将futureTask的对象作为参数传递到Thread构造器中,创建Thread的对象并调用start()方法
- 获取Callable中call()方法的返回值
package Thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 线程创建方式三:
* 实现Callable接口去完成多线程的创建
* @author Muluo
* @create 2021-01-19 21:38
*
*/
class NumThread implements Callable{
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(i);
sum += i;
}
}
// int 不是 Object的子类,所以此处sum为包装类
return sum;
}
}
public class ThreadNew {
public static void main(String[] args) {
NumThread numThread = new NumThread();
FutureTask futureTask = new FutureTask(numThread);
new Thread(futureTask).start();
try {
// get()方法返回值即为futureTask构造器参数,实现类重写的call()的返回值
Object sum = futureTask.get();
System.out.println("总和为" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
5、方式四:使用线程池(JDK5.0新增)
好处:
- 提高响应速度(减少线程创建的时间)
- 降低资源消耗(重复利用线程池章的线程,不需要每次都创建)
- 便于线程管理
1.提供指定线程数量的线程池
2.执行的指定操作,提供一个实现Runable或Callable接口实现类的对象
3.关闭连接池
package Thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 创建多线程的方式四:
* 使用线程池
* @author Muluo
* @create 2021-01-21 19:10
*/
class NumberThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
public class ThreadPool {
public static void main(String[] args) {
// 1.提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// 设置线程池的属性
// System.out.println(service.getClass());
ThreadPoolExecutor service1 = (ThreadPoolExecutor)service;
service1.setCorePoolSize(15);
// service1.getKeepAliveTime();
//2.执行的指定操作,提供一个实现Runable或Callable接口实现类的对象
service.execute(new NumberThread()); // 适用于Runnable
service.execute(new NumberThread1());
// service.submit(); // 适合用于Callable
// 3.关闭连接池
service.shutdown();
}
}