多线程

多线程的基本概念

1.什么是进程?

一个进程对应对应一个应用程序。例如:在windows操作系统启动Word就表示启动了一个进程。在java的开发环境下启动jvm,就表示启动了一个进程。现代的计算机都是支持多进程的,在同一个操作系统中,可以同时启动多个进程。

2.多进程有什么作用?

单进程计算机只能做一件事。对于单进程计算机来讲,在同一个时间点上,游戏进程和音乐进程是同时在运行吗?不是,因为计算机的CPU只能在某个时间点上做一件事。由于计算机将在“游戏进程”和“音乐进程”之间频繁切换执行,切换速度极高,人类感觉游戏和音乐在同时进行。

多进程的作用不是提高执行速度,而是提高CPU 的使用率

进程与进程之间的内存是独立的。

3.什么是线程?

线程是一个进程中的执行场景,线程是进程的执行单元。一个进程可以启动多个线程。线程之间相互独立的。

一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

4.多线程有什么作用?

多线程不是为了提高执行速度,而是提高应用程序的使用率。线程和线程共享“堆内存和方法去内存”,栈内存是独立的,一个线程一个栈。可以给现实世界中的人类一种错觉:感觉多个线程在同时并发执行。

并发性和并行性:并行性是指同一时刻,多条指令在多个处理器上同时执行;并发性是指同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

归纳

一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线程。

操作系统可以同时执行多个任务,每个任务就是一个进程;进程可以同时执行多个任务,每个任务就是线程。

5.java程序的运行原理

java命令会启动jvm,等于启动了一个应用程序,表示启动了一个进程。该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法。所以main方法运行在主线程中。在此之前的所有程序都是单线程的。

分析以下程序有几个线程

以下程序只有一个线程,就是主线程。
main,m1,m2,m3这四个方法在同一个栈空间中,没有启动其他任何线程。
public class Test{
    public static void main(String[] args){
        
        m1();
    }
    
    public static void m1(){
        
        m2();
    }
    
    public static m2(){
        
        m3();
    }
    
    public static void m3(){
        
        System.out.println("m3....");
    }
}

在java语言中实现多线程的方式

第一种方式:继承java.lang.Thread;,然后重写run方法
如何定义线程?
如何创建线程?
如何启动线程?
public class Test{
    
    public static void mian(String[] args){
        
        //创建线程
        Thread t = new Processor();
        
        //启动
        //这段代码执行瞬间结束,告诉jvm再分配一个新的栈给t的线程
        //run不需要程序员手动调用,系统线程启动之后自动调用run方法
        t.start();
        
        //t.run(); 这是普通方法调用,这样做程序只有一个线程,run方法结束后,下面程序继续执行
        
        //这段代码在主线程中运行
        for(int i=0;i<10;i++){
            
            System.out.println("main-->"+i);
        }
        
        //有了多线程之后,main方法结束只是主线程栈中没有方法栈帧了
        //但是其他线程或者其他栈中海油栈帧
        //main方法结束,程序可能还在运行
    }
}

//定义一个线程
class Processor extends Thread{
    
    //重写run方法
    public void run(){
        
        for(int i=0;i<100;i++){
            
            System.out.println("run-->"+i);
        }
    }
}
第二张方式:第一步:实现java.lang.Runnable;接口 第二步:实现run方法
public class ThreadTest03{
    
    public static void main(String[] args){
        
        //创建线程
        Thread t = new Thread(new Processor());  //new Processor()代表Runable
        
        //启动
        t.start();
        
    }
    
}

//推荐这种方式。因为一个类实现接口之外保留了类的继承
class Processor implements Runable{
    
    public void run(){
        
        for(int i=0;i<10;i++){
            
            System.out.println("run-->"+i);
        }
    }
}

线程生命周期

新建(new)的线程,调用start方法进入就绪状态,就绪状态的线程有权利拿到CPU时间片,拿到时间片后进入到运行状态,run方法执行,时间片用完后,再回到就绪状态,等待获取CPU时间片,再次获得时间片后,再次进入运行状态,然后接着运行run方法,不是从头开始运行,如此反复,直到run方法执行结束,线程消亡。

运行过程中可能遇到阻塞时间,等阻塞解除后,又会回到就绪状态。

五个状态:新建,就绪,运行,阻塞,消亡

补。图

线程的调度与控制

通常我们计算机只有一个CPU,CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。在单CPU的机器上线程不是并行运行的,只有在多个CPU上线程才可以并行运行。jvm要负责线程的调度,取得CPU的使用权,目前有两种调度模型:分时调度模型和抢占式调度模型,java使用抢占式调度模型。

分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片

抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。

三个方法

1.获取当前线程对象Thread.currentThread();

2.获取线程的名字 t.getName();

3.给线程取名 t.setName(“t1”);

public class ThreadTest{
    
    public static void main(String[] args){
        
        //如何获取当前线程对象?
        Thread t = Thread.currentThread(); //t保存的内存地址指向的线程是“主线程对象”
        
        //获取线程的名字
        System.out.println(t.getName());
        
        Processor p = new Processor();
        
        Thread t1 = new Thread(p);
        
        //给线程取名
        t1.setName("t1");
        
        t1.start();
        
        Thread t2 = new Thread(new Processor());
        
        t2.setName("t2");
        
        t2.start();
    }
}

class Processor implements Runnable{
    
    public void run(){
        
        Thread t = Thread.currentThread(); //t保存的内存地址指向的线程是“t1线程对象”
        
         System.out.println(t.getName());
    }
}

线程优先级

线程优先级主要分三种:MAX_PRIORITY(最高级-10);MIN_PRIORITY(最低级-1);NORM_PRIORITY(标准)默认-5

线程优先级高的获取的CPU时间片相对多一些

优先级:1-10

最低1

最高10

默认5

public class ThreadTest{
    
    public static void mian(String[] args){
        
        Thread t1 = new Processor();
        t1.setName("t1");
        
        Thread t2 = new Processor();
        te.setName("t2");
        
        System.out.println(t1.getPriority());  //默认5
        System.out.println(t2.getPriority());  //默认5
        
        //设置优先级
        t1.setPriority(4);
        t2.setPriority(6);
        
        //启动线程
        t1.start();
        t2.seart();
        
        
        
        
    }
}

class Processor extends Thread{
    
    public void run(){
        
        for(int i=0;i<50;i++){
            
            System.out.println(Thread.currentThread().getName()+"--->"+i);
            
        }
    }
}

1.Thread.sleep(毫秒)

2.sleep方法是一个静态方法

3.该方法的作用:阻塞当前线程,腾出CPU,让给其他线程

public class ThreadTest{
    
    public static void main(String[] args){
        
        Thread t1 = new Processor();
        
        t1.setName("t1");
        
        t1.start();
    }
}

class Processor extends Thread{
    
    //Thread中的run方法不抛出异常,所以重写run方法后,在run方法的声明位置上不能用throws
    //所以run方法中的异常只能try...catch..
    public void run(){
        
        for(int i=0;i<10;i++){
            
            System.out.println(Thread.currentThread().getName()+"-->"+i);
            
            try{
            
                Thread.sleep(1000);  //  让当前线程阻塞1s
                
            }catch(InterruptedException e){
            
                e.printStackTrace();
                
            }
        }
    }
}

线程同步

异步编程模型:t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁

同步编程模型:t1线程和t2线程执行,t1线程必须等t2线程执行结束之后,t1线程才能执行

什么时候同步?为什么要引入线程同步?

为了数据安全。尽管应用程序的使用率降低,但是为了保证数据是安全的,必须加入线程同步机制。线程同步机制使程序变成了(等同)单线程

什么条件下使用线程同步?

第一:必须是多线程环境

第二:多线程环境共享一个数据

第三:共享的数据涉及到修改操作

后续待补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值