单线程
在JavaSE中学习的程序,基本都是单线程的,也就是程序从main()方法进入之后按照顺序执行,如果程序中的某一个地方出现问题,那么整个程序就会出现问题,参考一下JavaSE中的运行时异常,如果没有经过处理,那么程序会崩溃。这就足以说明单线程程序是比较脆弱以及有相对的局限,这也就是单线程的脆弱性和局限性
当然也可以把单线程看成一个队列,程序每要执行一个线程,就相当于入队,也就是按照顺序,直到执行完成。
多线程
多线程就是指一个应用程序(也就是进程)中有多个并发执行的线程,他们会进行交替执行,并且共享进程的内存资源。
1、线程概述
1.1 进程
进程是操作系统中的概念,每一个独立执行的程序都能够称为一个进程。
比较简单的的理解,进程就是正在运行的程序。我们打开任务管理器就能够看到当前正在运行的进程。
当我们同时打开多个应用的时候,我们能看到多个进程在同时运行,其实这些进程都是并发进行的,也就是宏观上是同时进行,微观上是交替运行(此处有并发和并行的关系,并发可以理解为同一时间间隔内进行,并行可以理解为同一时间进行),此时进程能够并发执行的原因就是因为CPU能够在非常短的时间内在不同的进程之间切换。
- 进程是资源分配的最小单位
- 没有线程的情况下,进程是CPU调度的最小单位
- 在有线程的情况下,线程是CPU调度的最小单位
1.2 线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
一个代码也算是一个进程,如果程序按照从上往下的顺序执行,不是多段程序交替执行的,那么这个程序就是单线程程序。
如果需要多段程序交替执行,则需要创建多个线程,这就是多线程程序。
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程特点
- 每个线程之间都是独立的,他们可以并发执行
- 能够充分利用CPU资源,进一步提升程序执行效率。
2、线程创建
Java中通过三种方式创建多线程
- 继承Thread类,重写 run() 方法
- 实现Runnable接口,重写 run() 方法
- 实现Callable接口,重写 call() 方法,并使用 Future 来获取 call() 方法的返回结果
2.1 Thread类实现多线程
1、定义线程的主体类
我们需要通过集成Thread类,之后重写run方法。
package lianxi;
public class MyThread extends Thread { // 线程主体类
private String title ;
public MyThread(String title) {
this.title = title;
}
@Override
public void run() { // 所有线程从此处开始执行
for (int i = 0; i < 10 ; i++) {
System.out.println(this.title+",i = " + i);
}
}
}
之后定义测试类
package lianxi;
public class TestDemo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("thread1") ;
MyThread myThread2 = new MyThread("thread2") ;
MyThread myThread3 = new MyThread("thread3") ;
myThread1.run();
myThread2.run();
myThread3.run();
}
}
此处通过运行就可以看到,并不是交替打印的,和多线程一点关系没有。
主要是因为正确启动多线程的方式是调用Thread类中的start()方法。
启动多线程:public synchronized void start()此方法会自动调用线程的run()方法
以下才是正确的启动方式
public class TestDemo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("thread1") ;
MyThread myThread2 = new MyThread("thread2") ;
MyThread myThread3 = new MyThread("thread3") ;
myThread1.start();
myThread2.start();
myThread3.start();
}
}
这样启动之后,就可以看到交替运行的结果。
2.2 Runnable()接口实现多线程
class MyThread implements Runnable { // 线程主体类
private String title ;
public MyThread(String title) {
this.title = title;
}
@Override
public void run() { // 所有线程从此处开始执行
for (int i = 0; i < 10 ; i++) {
System.out.println(this.title+",i = " + i);
}
}
}
此时MyThread 类继承的不再是Thread类而实现了Runnable接口,虽
然解决了单继承局限问题,但是没有start()方法被继承了。那么此时就需要关注Thread类提供的构造方
法。
Thread类提供的构造方法:
public Thread(Runnable target)
可以接收Runnable接口对象。
启动多线程
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();
}
}
也可以采用匿名内部类的方式来创建
public class TestDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
}).start();
}
}
Runnable实现的多线程的程序类可以更好的描述出程序共享的概念
2.3 Callable实现多线程
Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。
class MyThread implements Callable<String> {
private int ticket = 10 ; // 一共10张票
@Override
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());
}
}

1317

被折叠的 条评论
为什么被折叠?



