把java基础撸一边,从简单的开始html
学习多线程,首先要了解多线程。有不少概念仍是要了解一下java
推荐连接:线程和进程的区别,很详细(若是这个看了,下面的几段文字能够过,抄的)多线程
有两种程,进程和线程并发
进程,是并发执行的进程在执行过程当中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。ide
线程,线程是进程的一部分,一个没有线程的进程能够被看做是单线程。线程有时又被成为轻量级进程,也是CPU调度的一个基本单位学习
线程的改变只表明CPU的执行过程的改变,而没有发生进程所拥有的资源变化。除了CPU以外,计算机的软硬件资源分配与线程无关,线程只能共享它所属进程的资源。this
与进程控制表和PCB类似,每一个线程也有本身的线程控制表TCB,而这个TCB中所保存的线程状态则比PCB表少得多,这些信息主要是相关指针用堆栈(系统栈和用户栈),寄存器中的状态数据。spa
进程拥有一个完整的虚拟机地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有本身的地址空间,与进程内的其余线程一块儿共享给该进程的全部资源。线程
java线程生命周期图(这图是我照着画的):
若是有兴趣的话,也能够画画。
如下是我乱逼逼,本身的认识。最好看官方的
线程的生命状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态
阻塞状态的时候,有两个定义,等待,和堵塞。等待:(理解)线程要进入的CPU被其余线程占用,服务执行该线程的任务。阻塞状态,代码notify()方法,或者说,除系统通知外叫醒这个线程的是等待。而堵塞是系统叫醒,好比sleep()。睡眠玩时间以后,系统会通知这个线程结束了。
Thread对象实例化后执行start()方法并无立刻去执行run()方法,而是在在Runnable就绪状态去抢夺CPU资源开始运行。起跑100米也要准备如下start()后就是须要准的强制CPU资源的那一瞬间,到了Running运行状态后若是执行完毕或者有异常退出,这个线程也就执行完毕Dead死亡了。
但还有可能在运行过程当中出现堵塞情况,好比sleep()睡眠,join()方法就会出现堵塞,当sleep结束或者join终端,I/O完成的时候会从新到Runnable准备去抢占CPU资源,而正在执行的Running的线程在yield的时候就与礼让CPU资源 进入Runnable状态
在Running状态的时候synchronize会进入锁,这个时候会等待处理一下。当同步锁被释放的时候会进入Runnable再去抢占资源
在Running状态的时候synchronize状态后wait()释放锁等待再到notify()唤醒锁,再次走当上面刚刚说的堵塞中。这里就基本了解了线程的运行状态
这是上面我推荐的博客上面的
下面是基本的使用,线程有两个中重要的类,一个是抽象类,Runnable,一个是Runnable实现类Thread。使用线程的时候通常是new Thread().start();这样就能够开启一个线程
还有就是实现Runnable的类,好比A实现了Runnable类,
A a = new A;
new Thread(a).start();这样也能够开启一个线程。二者的实现不一样来自于对Thread类不一样的构造方法不一样
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}复制代码
在来看看Runnable类
public interface Runnable {
public abstract void run();
}复制代码
run()方法里面就是这个线程的执行内容。
再来看看Thread的start()方法
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();复制代码
看到native就知道是去调用C代码
start0()方法会新运行一个线程,新线程会调用run()方法。
public void run() {
if (target != null) {
target.run();
}
}复制代码
这样一来就能够理清楚继承Thread类和实现Runnable类两种基本用法的区别
经过继承Thread类的须要去实现Thread。由于在构建方法中init方法是传递的null去赋值的。若是是建立传递了Runnable中,是传递过去。而且赋值,这样再run()方法中判断了target()而且运行了该实现Runnable类的run()方法
知道这个代码背景,就对线程的使用有了一个概念。
public class Demo1 extends Thread{
public Demo1(String name){
super(name);
}
@Override
public void run() {
while (!interrupted()) {
System.out.println("线程 :"+getName());
}
}
public static void main(String[] age){
Demo1 a = new Demo1("A");
a.start();
}
}复制代码
继承Thread的实现
public class Demo2 implements Runnable {
public static void main(String[] age){
Demo2 demo2 = new Demo2();
Thread thread = new Thread(demo2);
thread.start();
}
public void run(){
while (true){
System.out.println("thread running ...");
}
}
}复制代码
实现抽象类的Runnable