什么是进程?
- 进程是指运行中的程序,比如我们使用了QQ,就启动了一个进程,操作系统就会为进程分配内存空间,当我们使用一个其他的软件、程序,又启动了一个进程,操作系统将为启动的程序分配新的内存空间。
- 进程是程序的一次执行的过程,或者正在运行的一个程序。是一个动态的过程:具有自身的产生、存在和消亡的过程。
什么是线程
- 线程是进程创建的,是进程的一个实体。
- 一个进程可以有多个进程。
- 单线程:同一时刻,只允许执行一个线程
- 多线程:同一时刻,可以执行多个线程。例子:一个QQ程序可以同时打开多个聊天的会话。一个迅雷进程,可以同时下载多个文件。
- 并发:同一时刻,多个任务交替执行,(CPU通过调度算法来进行任务交替执行:例如:先来先服务,时间片轮转等)造成一种” 同时执行的假象“,简单的来说,单核CPU实现多任务的就是并发。
- 并行:同一时刻,多个任务同时执行。必须要满足CPU是多核的。
- 获取cpu核心数。
int i = Runtime.getRuntime().availableProcessors();
创建线程的两种方式:
- 继承Thread类,重写run方法 。
- Thread类也是实现了Runnable接口
- 当一个类继承了Thread类,该类就可以当作一个线程使用
- 实现Runnable接口,重写run方法。
第一种方式:
public class ThreadUse extends Thread{
public static void main(String[] args) {
ThreadUse threadUse = new ThreadUse();
threadUse.start();
}
@Override
public void run() {
int i=0;
while (true){
try {
sleep(1000);//单位是毫秒
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println("我是傻逼!"+i);
i++;
}
}
}
可以输入命令:在终端执行jconsole命令 查看线程的执行情况。
选择你的你的类所在的 路径
再选择不安全的连接
选择线程这一选项,就可以看到进程执行的情况
ThreadUse threadUse = new ThreadUse();
threadUse.start();
for (int i = 0; i <1000; i++) {
sleep(1000);
System.out.println("kkkkk");
}
会发现。main进程会和TreadUse交替运行。但是执行的结果不同。
线程执行的机制:
- 当一个程序在点击运行时,他会先创建一个main线程,而main线程能又会创建其他的线程。
- main线程,和创建的一起执行。如果时多核CPU这可能会出现并发,和并行。单核的话,就是并发。
解惑:
为什么我们不直接调用run方法来直接,而是调用start来启动多线程呢?
- 当我们开始在调用run方法,就相当于对象调用了一个普通的方法,不能够去创建线程。
- start方法中有一个 start0 方法(本地方法) 而start0方法才是创建线程的方法。并且是由jvm去执行。并且jvm执行了,也不会直接执行新的线程,而是把线程的状态转成可运行的状态,具体什么时候执行,他还要等CPU的调度。由cpu来做决定。或者根据CPU的调度算法。
第二种方式:
为何要实现Runnable的接口去实现多线程呢?
- java 是单继承,在某些情况下一个类可能已经继承了某一个父类,这时再用继承Thread类,来创建线程就不可能了。
- 所以出现了实现Runnable接口来创建线程。
class ThreadUse2 implements Runnable{
public static void main(String[] args) {
ThreadUse2 threadUse2 = new ThreadUse2();
//需要创建一个Thread对象,用Thread对象去调用start方法。
Thread thread = new Thread(threadUse2);
thread.start();
}
@Override
public void run() {
int i=0;
while (true){
try {
sleep(1000);//Thread的静态方法,要引入
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println("我是傻逼!"+i);
i++;
}
}
}
线程的常用方法:
Sellman sellman1 = new Sellman("小王");
Thread thread = new Thread(sellman1);
thread.interrupt();//中断线程,常用于唤醒正在休眠的线程。
thread.setName("lalal");//设置线程名
thread.getName();//得到线程名
thread.setPriority(Thread.NORM_PRIORITY);//设置线程的优先级,MIN_PRIORITY =1
// MAX_PRIORITY= 10 NORM_PRIORITY = 5
thread.getPriority();//得到线程的优先级
yield: 线程的礼让,让出CPU,让其他的线程执行,但是礼让的时间不确定,所以也不一定礼让成功。
join:线程的插队。插队的线程一旦插入成功,则肯定将执行插入的所有的任务
Sellman sellman2 = new Sellman("老王");
Thread thread1 = new Thread(sellman2);
thread1.start();
thread.join();//thread插队,就先执行thread
用户线程和守护线程
-
用户线程:也叫做工作线程,当线程的任务执行完成或者通知方式结束
-
守护线程:一般为工作线程服务的,当所有的用户线程结束,守护线程自动结束。
-
最常见的守护线程就是:垃圾回收机制
线程的状态:线程状态。 线程可以处于以下状态之一: NEW 尚未启动的线程处于此状态。 RUNNABLE (ready状态 running状态) 在Java虚拟机中执行的线程处于此状态。 BLOCKED 被阻塞等待监视器锁定的线程处于此状态。 WAITING 无限期等待另一个线程执行特定操作的线程处于此状态。 TIMED_WAITING 正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。 TERMINATED 已退出的线程处于此状态。 线程在给定时间点只能处于一种状态。 这些状态是虚拟机状态,不反映任何操作系统线程状态。
线程的同步机制
- 在多线程编程,一些敏感的数据(临界资源)不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任意时刻,最多只有一个线程访问,以保证数据的完整性。
- 线程同步:既当有一个线程在对内存进行操作的时候,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存的地址进行操作。
同步的具体使用方法 ——Synchronized
-
同步代码块
synchronized (对象){//得到对象的锁,才能操作同步代码 //需要同步的代码 }
-
synchronized还可以放在方法声明中,表示整个方法 —— 为同步方法
public synchronized void m(){ //需要同步的代码 }
public class moreThread {
public static void main(String[] args) throws InterruptedException {
Sellman sellman1 = new Sellman("小王");
Thread thread = new Thread(sellman1);
thread.start();
// thread.interrupt();//中断线程,常用于唤醒正在休眠的线程。
// thread.setName("lalal");//设置线程名
// thread.getName();//得到线程名
// thread.setPriority(Thread.NORM_PRIORITY);//设置线程的优先级,MIN_PRIORITY =1
// // MAX_PRIORITY= 10 NORM_PRIORITY = 5
//
// thread.getPriority();//得到线程的优先级
//
//
Sellman sellman2 = new Sellman("老王");
Thread thread1 = new Thread(sellman2);
thread1.start();
}
}
class Sellman implements Runnable{
private String name;
private Boolean loop =true;
public Sellman(String name) {
this.name = name;
}
public synchronized void sell(){
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正在买票的人是:" + name + "当前票数为" + tickets--);
if (tickets <= 0) {
System.out.println("票已经卖完了!");
loop = false;
}
}
static int tickets=100;
@Override
public void run() {
while (loop) {
sell();
}
}
}