Java多线程的实现:
1.继承Thread类
步骤:
(1)创建一个Thread线程类的子类(子线程),同时重写Thread类的run方法;
(2)创建稿子类的实例对象,并通过调用start()方法启动线程。
示例1:
class MyThread extends Thread {
private String title;
public MyThread(String title) {
this.title = title;
}
/*
* 这里我们自然会想到产生线程的实例化对象后调用run()方法,实际上我们不能直接去调用run()方法
*/
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.title + ",i=" + i);
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("Thread1");
MyThread myThread2 = new MyThread("Thread2");
MyThread myThread3 = new MyThread("Thread3");
/*
* 这时候只进行了顺序打印,和多线程无关。正确启动多线程能够的方式是调用Thread类中的start()方法 myThread1.run();
* myThread2.run(); myThread3.run();
*/
myThread1.start();
myThread2.start();
myThread3.start();
}
}
已注释代码部分的顺序执行结果:
正确的运行结果:
示例2(示例1中的部分代码片段):
public class TestDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread("Thread1");
myThread.start();
System.out.println("运行结束!");
}
}
运行结果:
运行结果发现MyThread.java类中的run()方法的执行时间相对于“运行结束!”的执行时间晚,因为start()方法执行比较耗时。
耗时原因:
1)通过JVM告诉操作系统创建Thread;
2)操作系统开辟内存并使用Windows SDK中的creatThread()函数创建Thread线程对象;
3)操作系统对Thread对象进行调度,以确定执行时机;
4)Thread在操作系统中被成功执行。
人为改变输出结果可以在调用start()方法后面调用函数sleep();
具体实现:Thread.sleep(200);
示例3:线程随机性的展现
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("run=" + Thread.currentThread().getName());
}
}
}
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.setName("myThread");
myThread.start();
for (int i = 0; i < 10; i++) {
System.out.println("main=" + Thread.currentThread().getName());
}
}
}
运行结果:
多线程随机输出的原因是CPU将时间片分给不同的线程,线程获得时间片后就执行任务,所以这些线程在交替地执行并输出,导致输出结果呈现乱序的效果。时间片即CPU分配给各个程序的时间。每个线程被分配一个时间片,在当前的时间片内CPU去执行线程中的任务。需要注意的是,CPU在不同的线程上进行切换时需要耗时的,所以并不是线程创建的越多,软件运行效率就越高,相反,线程数过多反而会降低软件的执行效率。
示例4:执行start()的顺序并不代表执行run()的顺序
class MyThread extends Thread {
private int title;
public MyThread(int title) {
this.title = title;
}
public void run() {
System.out.println(title);
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread(1);
MyThread myThread2 = new MyThread(2);
MyThread myThread3 = new MyThread(3);
MyThread myThread4 = new MyThread(4);
MyThread myThread5 = new MyThread(5);
MyThread myThread6 = new MyThread(6);
myThread1.start();
myThread2.start();
myThread3.start();
myThread4.start();
myThread5.start();
myThread6.start();
}
}
运行结果:
2.实现Runnable接口
———通过继承Thread类的方式实现了多线程,但这种方式有一定局限性,因为Java只支持类的单继承,如果某个类已经继承了其他父类,就无法再继承Thread类来实现多线程。在这种情况下,就可以考虑实现Runnable()方法来实现多线程。
步骤:
1)创建一个Runnable接口的实现类,同时重写接口中的run()方法;
2)创建Runnable接口的实现类对象;
3)使用Thread有参构造方法创建线程实例,并将Runnable接口的实现类的实例对象作为参数传入;
4)调用线程实例的start()方法启动线程。
class MyThread implements Runnable {
private String title;
public MyThread(String title) {
this.title = title;
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(this.title + ",i=" + i);
}
}
}
/*
* 程序写到这里会发现,此时MyThread类继承的不再是Thread类而实现了Runnable接口,
* 虽然解决了单继承局限问题,但是没有start方法被继承了。 这时就要关注Thread类提供的构造方法。 public Thread(Runnable
* target) 作用:可以接收Runnable接口对象
*/
/*
* 多线程的启动永远都是Thread类的start()方法
*/
public class TestDemo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("thread1");
MyThread myThread2 = new MyThread("thread2");
MyThread myThread3 = new MyThread("thread3");
new Thread(myThread1).start();
new Thread(myThread2).start();
new Thread(myThread3).start();
}
}
运行结果:
对于此时的Runnable接口对象可以采用匿名内部类或者Lambda表达式来定义
//匿名内部类
public class TestDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("Hello World");
}
}).start();
}
}
//Lambda表达式
public class TestDemo {
public static void main(String[] args) {
Runnable runnable=()->System.out.println("Hello World");
new Thread(runnable).start();
}
}
3.线程类的继承结构
在多线程的处理上使用的就是代理设计模式。除了以上的关系之外,实际上在开发之中使用Runnable还有一个特点:使用Runnable实现的多线程的程序类可以更好的描述出程序共享的概念(并不是说Thread不能)
示例1:使用Thread实现数据共享(产生若干线程进行同一数据的处理操作)
此时启动三个线程实现买票处理,结果变成了买各自的票。
class MyThread extends Thread {
private int ticket = 5;// 一共5张票
public void run() {
while (ticket > 0) {
System.out.println("剩余票数:" + this.ticket--);
}
}
}
public class TestDemo {
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
new MyThread().start();
}
}
运行结果:
示例2:使用Runnnable实现共享
class MyThread implements Runnable {
private int ticket = 5;// 一共5张票
public void run() {
while (ticket > 0) {
System.out.println("剩余票数:" + this.ticket--);
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
运行结果:
4.Callable实现多线程
Runnnable中的run()方法没有返回值。它的设计也遵循了主方法的设计原则;线程一开始就不回头。但是很多时间需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。
//使用Callable定义线程主体类
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread implements Callable<String> {
private int ticket = 5;// 一共5张票
public String call() throws Exception {
while (this.ticket > 0) {
System.out.println("剩余票数:" + this.ticket--);
}
return "票已经售完";
}
}
//启动并取得线程的结果
public class TestDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<String> task = new FutureTask<>(new MyThread());
new Thread(task).start();
new Thread(task).start();
System.out.println(task.get());
}
}
运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190902165716591.png)