Java多线程(一)认识多线程
程序员文章站
2022-05-05 21:44:59
...
认识多线程
Java中有关多线程的只是虽然只有几章节,但是真正扩展开来几本书都不用,让我们从基础开始,一步步的学习多线程相关的知识。
1.基本概念介绍
进程:系统中分配资源的一个调度单位。线程:也被称为轻量级进程,是进城中的调度单位。
并发:多个指令轮流执行。
并行:多个执行同时执行。
一个程序至少有一个进程,一个进程中可以有多个线程。
2.多线程的基本实现
要想实现多线程,有以下三种方式:(1) 继承Thread类,
操作步骤:
- 定义Thread的子类,重写run()方法,作为线程执行体;
- 创建实例;
- 调用start()方法。
测试类:
package com.ljw.Thread.TestTickets;
/**
* Created by liujiawei on 2018/7/5.
*/
public class SellTickestByThread extends Thread{
public SellTickestByThread(String name) {
super(name);
}
int tickets = 10;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(tickets > 0)
System.out.println(getName() + "卖了以后还剩下==" + tickets--);
}
}
public static void main(String[] args) {
SellTickestByThread thread = new SellTickestByThread("一窗口");
SellTickestByThread thread1 = new SellTickestByThread("二窗口");
SellTickestByThread thread2 = new SellTickestByThread("三窗口");
thread.start();
thread1.start();
thread2.start();
}
}
运行结果:
运行上面的代码以后,我们可以看到多线程的确发挥了作用,三个窗口都开始售卖票了,但是每个窗口都卖了十张票,一共卖了三十张,这明显是不对的。这是因为继承Thread类的多线程无法共享线程类的实例变量。
(2)实现Runnable接口:
操作步骤:
- 实现Runnable,重写run()方法作为线程执行体;
- 创建Runnable类的实例,以此作为Thread的target来创建Thread实例。
我们还是用上面的例子来测试代码:
package com.ljw.Thread.TestTickets;
/**
* Created by liujiawei on 2018/7/5.
*/
public class SellTicketsByRunnable implements Runnable{
int tickets = 10;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(tickets > 0)
System.out.println(Thread.currentThread().getName() + "卖出以后还剩" + tickets--);
}
}
public static void main(String[] args) {
SellTicketsByRunnable sellTicketsByRunnable = new SellTicketsByRunnable();
Thread thread = new Thread(sellTicketsByRunnable,"窗口一");
Thread thread2 = new Thread(sellTicketsByRunnable,"窗口二");
Thread thread3 = new Thread(sellTicketsByRunnable,"窗口三");
thread.start();
thread2.start();
thread3.start();
}
}
运行结果:
我们可以看到,这次的结果好像是我们想要的情况,窗口卖票,但票的总数不会变多,可惜的是顺序好像不太多,这个我们以后在说。我们可以知道实现Runnable接口也可以实现多线程,而且还可以共享线程类的实例变量。
(3)使用Callable和Future创建线程:
Callable接口是Runnable接口的增强版,它提供了一个call()方法作为线程执行体,但是他可以有返回值,也可以返回报错时的异常。它和Future对象配合起来使用。1》创建Callable接口的实现类,重写call()方法作为线程实现体,且call()方法有返回值;
2》使用FutureTask对象来包装Callable对象,同时封装了call()方法的返回值;
3》使用FutureTask对象作为Thread对象的target创建Thread实例
4》使用FutureTask对象的get()方法可以获取call()方法的返回值。
下面我们看下测试代码:
package com.ljw.Thread.TestTickets;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* Created by liujiawei on 2018/7/6.
*/
public class SellTicketsByFuture implements Callable{
int tickets = 10;
@Override
public Object call() throws Exception {
for (int i = 0; i < 100; i++) {
if(tickets > 0)
System.out.println(Thread.currentThread().getName() + "卖出还剩" + tickets--);
}
return null;
}
public static void main(String[] args) {
SellTicketsByFuture sellTicketsByFuture = new SellTicketsByFuture();
FutureTask task = new FutureTask(sellTicketsByFuture);
FutureTask task2 = new FutureTask(sellTicketsByFuture);
Thread thread = new Thread(task,"窗口一");
Thread thread2 = new Thread(task2,"窗口二");
thread.start();
thread2.start();
}
}
输出结果:
可以看到使用Callable接口一样实现多线程的功能。
3.三种多线程创建方式的对比.
采用Runnable和Callable接口的优缺点:优点:(1)实现接口不影响继承,还可以再继承其他类;
(2)这两者都可以共享同一个target,可以分享同一个资源;
缺点:编程略复杂,获取线程要通过Thread.currentThread()这种方式
采用Thread继承的优缺点:
优点:(1)编程简单
(2)获取线程对象方便,this就可以;
缺点:无法继承其他类,无法共享target的实例变量。
上一篇: 多线程知识汇总