java学习 day 23 多线程 进程的概述和多进程的意义 线程的概述和多线程的意义 JVM运行原理以及JVM启动的线程探讨 实现多线程 线程调度 线程控制

23.01_多线程(进程概述及多进程的意义)

A:线程和进程
	要想说线程,首先必须得聊聊进程,因为线程是依赖于进程存在的。
B:进程概述
	什么是进程呢?通过任务管理器我们就可以看到进程的存在。
	概念:进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
				  每一个进程都有它自己的内存空间和系统资源。
C:多进程的意义
	单进程计算机只能做一件事情。而我们现在的计算机都可以一边玩游戏(游戏进程),一边听音乐(音乐进程),
	所以我们常见的操作系统都是多进程操作系统。比如:Windows,Mac和Linux等,能在同一个时间段内执行多个任务。
	对于单核计算机来讲,游戏进程和音乐进程是同时运行的吗?不是。
	因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和音乐进程间做着频繁切换,且切换速度很快,
	所以,我们感觉游戏和音乐在同时进行,其实并不是同时执行的。多进程的作用不是提高执行速度,而是提高CPU的使用率。

23.02_多线程(线程概述及多线程的意义及并行和并发的区别)

A:什么是线程
	在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位。所以,进程是拥有资源的基本单位, 线程是CPU调度的基本单位。
B:多线程有什么意义呢?
	多线程的作用不是提高执行速度,而是为了提高应用程序的使用率。
	那么怎么理解这个问题呢?
	我们程序在运行的使用,都是在抢CPU的时间片(执行权),如果是多线程的程序,那么在抢到
	CPU的执行权的概率应该比较单线程程序抢到的概率要大.那么也就是说,CPU在多线程程序
	中执行的时间要比单线程多,所以就提高了程序的使用率.但是即使是多线程程序,那么他们
	中的哪个线程能抢占到CPU的资源呢,这个是不确定的,所以多线程具有随机性.
C:大家注意两个词汇的区别:并行和并发。
	前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。
	后者是物理上同时发生,指在某一个时间点同时运行多个程序。
 什么是并发 ?
       并发 : 指应用能够交替执行不同的任务, 其实并发有点类似于多线程的原理, 多线程并非是如果你开两个线程同时执行多个任务。
 执行, 就是在你几乎不可能察觉到的速度不断去切换这两个任务, 已达到"同时执行效果", 其实并不是的, 只是计算机的速度太快, 我们无法察觉到而已. 就类似于你, 吃一口饭喝一口水, 以正常速度来看, 完全能够看的出来, 当你把这个过程以n倍速度执行时..可以想象一下.
        
 什么是并行 ?
     并行 : 指应用能够同时执行不同的任务, 例:吃饭的时候可以边吃饭边打电话, 这两件事情可以同时执行
        

23.03_多线程(Java程序运行原理和JVM的启动是多线程的吗)

A:Java程序运行原理
	Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。
	该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。
	所以 main方法运行在主线程中。
B:JVM的启动是多线程的吗:		JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

23.04_多线程(多线程程序实现的方式1)(掌握)

A:如何实现多线程:
如何实现呢?
	由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。
  		而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。
  		但是Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。
  		但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。
  		由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西,
  		然后提供一些类供我们使用。我们就可以实现多线程程序了。
	参考 Thread类
	B:多线程程序实现的方式1
		a:继承Thread类
		b:步骤及代码演示
		c:几个小问题:
			启动线程使用的是那个方法
			线程能不能多次启动
			run()和start()方法的区别
 我们启动线程使用不是run方法,而应该是start方法.使该线程开始执行;
	 Java 虚拟机调用该线程的 run 方法。
     
     为什么要重写run方法?
这个类是一个线程类,那么在这个类中我们可不可以写一些其他的方法呢?		
   我们可以在写其他的方法,那么其他方法中封装的代码都是需要被我们线程执行的吗? 不一定
   那么也就是run方法中封装应该是必须被线程执行的代码.
   
 run方法中的代码的书写原则: 一般是比较耗时的代码
 C:案例演示:	多线程程序实现的方式1		
 

public class MyThread extends Thread{

    @Override
    public void run() {
        //这个run方法就是需要线程来执行的代码,一般耗时的操作,我们就会写在run方法里面,让线程去执行
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }
}

public class MyTest3 {
    public static void main(String[] args) {
        //Java如何开启一个线程
        //我们可以使用Java提供的Thread这个类,来创建线程
        //创建线程的方式1
        //1.我们定义一个类,继承Thread这个类
        //2.重写Thread这个类中的run方法
        //3,创建我们写的类的对象
        //4.开启线程
        MyThread th = new MyThread();
        //开启线程,不是调用run方法,调用run()方法,就是你使用一个对象,调用一个方法,让这个方法执行而已,线程并没有开启
        //th.run();
        //正确开启线程的方式是,调用start() 开启线程,由线程去调用run()去执行run方法里面的代码
        th.start();
        //th.start(); 同一个线程不要多次开启,会抛异常
        MyThread th2 = new MyThread();
        th2.start();
    }
}

23.05_多线程(获取和设置线程对象名称)(掌握)

A:Thread类的基本获取和设置方法
	public final String getName()//获取线程名称
	public final void setName(String name)//设置线程名称
	其实通过构造方法也可以给线程起名字
	思考:
		如何获取main方法所在的线程名称呢?
		public static Thread currentThread()//获取当前执行的线程
		/**
	 * 我们现在是想获取主线程的名称,那么我们可不可以先获取到主线程,
	 如果我们能获取到主线程,那么我们就可以调用getName方法获取对应的名称.
	 * 如何获取主线程呢? public static Thread currentThread()返回对当前正在执行的线程对象的引用。 
	 */
B:案例演示:	获取和设置线程对象名称

import com.sun.media.sound.SoftTuning;


public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            //获取线程的名称
           // String name = this.getName();
            Thread thread = Thread.currentThread();
            String name = thread.getName();

            System.out.println(name+":"+i);
        }
    }

    public void show(){

    }
}

public class test2 {
    public static void main(String[] args) {
        Thread2 th1=new Thread2();
        th1.setName("aaa");
        th1.start();
    }
}


23.07_多线程(线程控制之休眠线程)(掌握)

A:线程休眠:	public static void sleep(long millis) 线程休眠
B:案例演示:	线程休眠



public class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run(){
        //String name = this.getName();
        String name1 = Thread.currentThread().getName();
        //让线程睡一会 就是让线程处于了一种阻塞状态
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 100; i++) {
            System.out.println(name1+i);
        }
    }
}



public class MyTest {
    public static void main(String[] args) throws InterruptedException {
        //通过构造 ,给线程设置名字
        MyThread th = new MyThread("张飞");
        th.start();
        Thread.sleep(3000); //让当前线程休眠
        System.out.println("abc");

    }
}

23.08_多线程(线程控制之加入线程)(掌握)

A:加入线程:	public final void join()
	意思就是: 等待该线程执行完毕了以后,其他线程才能再次执行
	注意事项: 在线程启动之后,在调用方法
B:案例演示:	加入线程

public class Thread4 extends  Thread{
    public Thread4(String name){
        super(name);
    }
    public void run(){
        String name=Thread.currentThread().getName();
        for(int i=0;i<100;i++)
        {
            System.out.println(name+"::"+i);
        }
    }
}
public class test4 {
    public static void main(String[] args) throws InterruptedException {
        Thread4 th4=new Thread4("线程4");
        Thread4 th3=new Thread4("线程3");
        Thread4 th2=new Thread4("线程2");
        Thread4 th1=new Thread4("线程1");


        th4.start();
        th4.join();
        th3.start();
        th3.join();
        th2.start();
        th2.join();
        th1.start();
        th1.join();
    }
}

23.09_多线程(线程控制之礼让线程)(了解)

A:礼让线程:	public static void yield():	暂停当前正在执行的线程对象,并执行其他线程。 
B:案例演示:	礼让线程
按照我们的想法,这个礼让应该是一个线程执行一次,但是通过我们的测试,效果好像不太明显.
那是为什么呢?
这个礼让是要暂停当前正在执行的线程,这个暂停的时间是相当短的,如果在这个线程暂停完毕以后,其他的线程还没有
抢占到CPU的执行权,那么这个时候这个线程应该再次和其他线程抢占CPU的执行权. 

23.10_多线程(线程控制之守护线程)(了解)?????

A:守护线程:	public final void setDaemon(boolean on):
	将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 
	该方法必须在启动线程前调用。 

 Java用户线程和守护线程
1.用户线程和守护线程的区别
    用户线程和守护线程都是线程,区别是Java虚拟机在所有用户线程dead后,程序就会结束。而不管是否还有守护线程还在运行,若守护线程还在运行,则会马上结束。很好理解,守护线程是用来辅助用户线程的,如公司的保安和员工,各司其职,当员工都离开后,保安自然下班了。
    
 2.用户线程和守护线程的适用场景
    由两者的区别及dead时间点可知,守护线程不适合用于输入输出或计算等操作,因为用户线程执行完毕,程序就dead了,适用于辅助用户线程的场景,如JVM的垃圾回收,内存管理都是守护线程,还有就是在做数据库应用的时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监听连接个数、超时时间、状态等。
    
 3.创建守护线程
    调用线程对象的方法setDaemon(true),设置线程为守护线程。
            1)thread.setDaemon(true)必须在thread.start()之前设置。
            2)在Daemon线程中产生的新线程也是Daemon的。
            3)不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。
    因为Daemon Thread还没来得及进行操作,虚拟机可能已经退出了。
    
 4.Java守护线程和Linux守护进程
    两者不是一个概念。Linux守护进程是后台服务进程,没有控制台。
    在Windows中,你可以运行javaw来达到释放控制台的目的,在Unix下你加&在命令的最后就行了。所以守护进程并非一定需要的。

23.11_多线程(线程控制之中断线程(清楚阻塞线程))(了解)

A:中断线程
	public final void stop():		停止线程的运行
	public void interrupt():		中断线程(这个翻译不太好),查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞

23.12_多线程(多线程程序实现的方式2)(掌握)

A:实现Runnable接口  这种方式扩展性强 实现一个接口 还可以再去继承其他类
	a:如何获取线程名称
	b:如何给线程设置名称
	c:实现接口方式的好处
		可以避免由于Java单继承带来的局限性。
B:案例演示:	多线程程序实现的方式2


public class MyRunnable implements Runnable{
    @Override
    public void run() {
        //需要线程执行
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }
}


public class MyTest {
    public static void main(String[] args) {
       //线程:一个进程中,正在执行的任务我们叫做线程
        //进程:正在执行的应用程序,一个应用程序,至少要包含一个线程
        //进程是拥有资源的基本单位, 线程是CPU调度的基本单位
        //并发:多个任务交替执行,Java多线程就是并发执行
        //并行:多个任务同时执行
        //开启线程的方式一
        //创建一个类,继承 Thread类,
        //2.重写run方法
        //3,创建该类的对象,调用start()方法开启线程
        //线程类中常用的方法,线程休眠,join()
        //开启线程的方式2
        //1.创建一个类,实现Runnable接口,重写改接口中的run方法
        //2.创建Thread类,对象,将Runnable接口的子类对象传递进来
        //3,调用start()方法开启线程

        MyRunnable myRunnable = new MyRunnable();
       // Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。
        //Thread(Runnable target)
        //分配新的 Thread 对象。
        Thread th = new Thread(myRunnable);
        th.start();

        new MyThread().start();
    }
}

23.12_多线程(多线程程序实现的方式3)(掌握)

A:实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
  
    B:执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。  FutureTask 是  Future 接口的实现类

C:实现步骤
	1.创建一个类实现Callable 接口
	2.创建一个FutureTask类将Callable接口的子类对象作为参数传进去
	3.创建Thread类,将FutureTask对象作为参数传进去
	4.开启线程

23.14_多线程(继承Thread类的方式卖电影票案例)(理解)

A:案例演示
	需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
	通过继承Thread类实现

 分析:
 a: 三个窗口其实就是3个线程
 b: 定义票的数量100张
 c: 创建线程对象,启动线程. 每卖一张这个票数应该--

public class MyRunnable8 implements Runnable{
static int piao=10000;
static Object obj=new Object();
@Override
public void run() {
while(true)
{
synchronized (obj)
{
if(piao>=1)
{
try {
Thread.sleep(10);
}catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+“正在出售”+(piao–));
}
}
}
}
}

public class test8 {
public static void main(String[] args) {
MyRunnable8 myRunnable=new MyRunnable8();
Thread th1=new Thread(myRunnable);
Thread th2=new Thread(myRunnable);
Thread th3=new Thread(myRunnable);
th1.start();
th2.start();
th3.start();
}
}

23.15_多线程(实现Runnable接口的方式卖电影票)(理解)

A:案例演示
	需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
	通过实现Runnable接口实现
	

23.16_多线程(买电影票出现了同票和负数票的原因分析)(理解)

A:加入延迟
	我们前面讲解过电影院售票程序,从表面上看不出什么问题,但是在真实生活中,
	售票时网络是不能实时传输的,总是存在延迟的情况,所以,在出售一张票以后,需要一点时间的延迟
	改实现接口方式的卖票程序,每次卖票延迟100毫秒
B:出现问题了问题

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值