1.进程:每一个程序都是一个进程,进程包含一个程序所需要的所有资源
2.线程:用来执行代码的工具
3.主线程:一个进程最少要包含的线程---main
程序会自动调用主线程的代码
4.子线程:通过主线程开启的线程
//线程的表现出形式
//1.继承Thread类,并重写run()方法,类似于主线程的main方法
//2.实现Runnable接口
线程的生命周期:
阻塞
/ \
/ \
1新建-->2就绪-->3运行-->4死亡 阻塞状态在2和3之间形成三足鼎立之势 |
线程无序调用的原因
cpu同时只能工作一个线程对象,其它线程会抢占资源,抢不到的线程会 |
同步的方式有两种
//1.同步的代码块 synchronized(被同步的对象){}
//2.同步的方法 public synchronized void add();
|
线程的同步
同步:同一时间只有一个对象可以被寄存器操作
异步:同一时间可以有多个对象可以被寄存器操作
|
两种方式所创建线程的对比
1.采用实现Runnable接口方式的多线程
----线程类只是实现了Runnable接口,还可以继承其他类
-----可以多个线程共享一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将cpu 代码 和数据分开,形成清晰的模型
|
创建线程的两种方式
方式1,继承Thread
1.1定义一个类继承Thread
1.2重写run()方法
1.3创建子类对象,就是创建线程对象
1.4调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法
|
:线程对象调用run()方法和调用start方法的区别?
调用run()方法不开启线程,仅是对象调用方法
调用start()开启线程 并让jvm调用run方法在开启的线程中执行
例子:
public class Demo2_Thread {
public static void main(String[] args) {
MyThread mt = new MyThread(); //4,创建自定义类的对象
mt.start(); //5,开启线程
for(int i = 0; i < 3000; i++) {
System.out.println("bb");
}
}
}
class MyThread extends Thread { //1,定义类继承Thread
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
}
方式2:实现Runnable接口
1.1定义类实现Runnable接口--->避免了单继承的局限性,将线程任务单独分离开来封装成对象,类型就是Runnable接口,对线程对象和线程任务进行解耦
1.2实现run方法--->将线程任务代码定义到run方法中
1.3把新线程要做的事情写在run方法中
1.4创建自定义的Runnable的子类的对象--->作为参数传给Thread类的构造函数
1.5创建Thread对象,传入Runnable
1.6调用start开启新线程,内部会自动调用Runnable的run()方法
|
例子如下:
public class Demo3_Runnable {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable(); //4,创建自定义类对象
//Runnable target = new MyRunnable();
Thread t = new Thread(mr); //5,将其当作参数传递给Thread的构造函数
t.start(); //6,开启线程
for(int i = 0; i < 3000; i++) {
System.out.println("bb");
} } }
class MyRunnable implements Runnable { //1,自定义类实现Runnable接口
@Override
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
} } }