目录
一、引言
之前多线程了解的基本是皮毛,后来是因为对javaweb中tomcat接受请求,用户并发访问如何使用多线程不太清楚,所以又重新把多线程拾了起来,发现了一片新大陆。
好多地方用到了多线程,使用同步以保证数据安全:collection中vector与arraylist线程安全,数据库中的读写锁互斥,消息队列中take与put的安全性,tomcat服务访问等等。
列了个大纲,写了下这一些列博客的内容梳理
二、多进程与多线程
一个进程对应一个应用程序。例如:在 windows 操作系统启动 Word 就表示启动了一个 进程。在 java 的开发环境下启动 JVM,就表示启动了一个进程。多进程的作用不是提高执行速度,而是提高 CPU 的使用率。
线程是一个进程中的执行场景,一个进程可以启动多个线程,线程之间共享java堆和方法区,不共享java栈。多线程不是为了提高执行速度,而是提高应用程序的使用率。
三、实现方法
首先介绍实现方法,这个是最直观的认识
1、继承Thread接口
public class Test {
public static void main(String [] args){
MyThread myThread=new MyThread();
myThread.start();
}
}
class MyThread extends Thread
{
@Override
public void run() {
while(true)
{
try {
Thread.sleep(1000);//该线程休息1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程——"+ Thread.currentThread().getName());
}
}
}
2、实现runnable接口,传入Thread运行
package com.thread;
public class Test {
public static void main(String [] args){
new Thread(new Runnable() {
public void run() {
while(true)
{
try {
Thread.sleep(1000);//该线程休息1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程——"+ Thread.currentThread().getName());
}
}
}).start();
}
}
这个是匿名内部类的形式把Runnable对象传入Thread的构造函数当中。
3、注意
其实还有callable方法,可以返回值以后再慢慢讲。这里我们必须调用Thread的start()方法,这样才能通过jvm开启一个多线程,直接调用Thread的run()方法只是调用一个简单点的函数。
还有个比较经典的问题,下面的程序输出什么(即在runnable中实现run方法,又在Thread中实现run方法,多线程会调用哪一个)
public class Test {
public static void main(String [] args){
new Thread(new Runnable() {
public void run() {
while(true)
{
try {
Thread.sleep(1000);//该线程休息1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程111——"+ Thread.currentThread().getName());
}
}
}){
public void run() {
while(true)
{
try {
Thread.sleep(1000);//该线程休息1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程222——"+ Thread.currentThread().getName());
}
}
}.start();
}
}
答案是Thread中的run方法,因为Thread类中run方法如下,target是传入的runnable对象,如果传入了runnable对象,就会执行runnable的run方法,但是现在Thread类中的run方法被继承,父类的run方法失效自然就不执行target.run方法,只会执行我们写好的继承类中的run方法。
@Override
public void run() {
if (target != null) {
target.run();
}
}
四、生命周期
一个线程和vue、activity、servlet一样也有自己生命周期,了解生命周期可以使我们更好的理解多线程。
新建状态:使用关键字new创建线程后,线程处于等待状态,等待start;
就绪状态:线程执行start,线程排入就绪队列,等待jvm调度器调度;
运行状态:当线程抢到cpu资源,执行run方法,这时可以进入阻塞、就绪、和死亡任意一个状态;
死亡状态:线程完成任务或者stop/interrupt,线程结束进入死亡状态;
阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
-
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
-
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
-
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
五、总结
- 多进程与多线程
- 实现方法
- 生命周期