• 线程和并发--基础


    概述

    并发和并行是即相似又有区别:

    • 并行:指两个或多个事件在同一时刻发生;
    • 并发:指两个或多个事件在同一时间段内发生。

    进程是指一个内存中运行中的应用程序。每个进程都有自己独立的一块内存空间,一个应用程序可以同时启动多个进程。比如在Windows系统中,一个运行的abc.exe就是一个进程。
    那么我们此时就可以处理同时玩游戏和听音乐的问题了,我们可以设计成两个程序,一个专门负责玩游戏,一个专门负责听音乐。
    但是问题来了,要是要设计一个植物大战僵尸游戏,我得开N个进程才能完成多个功能,这样的设计显然是不合理的。
    更何况大多数操作系统都不需要一个进程访问其他进程的内存空间,也就是说进程之间的通信很不方便。
    此时我们得引入“线程”这门技术,来解决这个问题。

    线程是指进程中的一个执行任务(控制单元),一个进程可以同时并发运行多个线程,如:多线程下载软件。
    一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行任务,即多线程。
    多进程:操作系统中同时运行的多个程序。
    多线程:在同一个进程中同时运行的多个任务。
    我们查看Windows环境下的任务管理器:
    在操作系统中允许多个任务,每一个任务就是一个进程,每一个进程也可以同时执行多个任务,每一个任务就是线程。

    多线程作为一种多任务、并发的工作方式,当然有其存在优势:

    • 进程之前不能共享内存,而线程之间共享内存(堆内存)则很简单。
    • 系统创建进程时需要为该进程重新分配系统资源,创建线程则代价小很多,因此实现多任务并发时,多线程效率更高.
    • Java语言本身内置多线程功能的支持,而不是单纯第作为底层系统的调度方式,从而简化了多线程编程.

    用java语言创建进程

    import java.io.IOException;
    //如何用java语言开启一个进程
    public class ProcessDemo {
    	public static void main(String[] args) throws IOException{
    		//方式一:使用Runtime的exec方法
    		Runtime.getRuntime().exec("notepad");
    		//方式二:使用ProcessBuilder类中的start方法
    		ProcessBuilder pb = new ProcessBuilder("notepad");
    		pb.start();
    	}
    }
    
    

    创建和启动线程

    方式一:继承Thread类

    1. 自定义类继承于Thread类,那么该自定义类就是线程类;

    2.覆写run方法,将线程运行的代码存放在run中;

    3.创建自定义类的对象,即线程对象;

    4.调用线程对象的start方法,启动线程。

    package thread_create;
    //继承方式 创建和启动线程
    class MusicThread extends Thread{      //MusicThread是线程子类
    	public void run() {               //子类必须重写run()方法
    		for(int i = 0 ;i < 50;i++)
    		{
    			System.out.println("听音乐"+i);
    		}
    	}
    	
    }
    public class ExtendsThreadDemo {
    	public static void main(String[] args){
    		for(int i = 0 ;i < 50;i++)
    		{
    			System.out.println("玩游戏"+i);
    			if( i == 10){
    				MusicThread t = new MusicThread();  //创建线程子类的实例
    				t.start(); //底层也调用了run();  启动线程
    			}
    		}
    			
    	}
    }
    
    

    方式二:实现Runnable接口

    1.自定义类实现Runnable接口;

    2.覆写run方法,线程运行的代码存放在run中;

    3.通过Thread类创建线程对象,并将实现了Runnable接口的实现类对象作为参数传递给Thread类的构造器。

    4.Thread类对象调用start方法,启动线程。

    class MusicRunnable implements java.lang.Runnable{         //注意MusicRunnable类不是线程类或者线程子类
    	public void run() {									   //接口的实现必须覆盖方法。				
    		for(int i = 0 ;i < 50;i++)
    		{
    			System.out.println("听音乐"+i);
    		}
    	}
    }
    public class ImplementsRunnableDemo {
    	public static void main(String[] args){
    		for(int i = 0 ;i < 50;i++)
    		{
    			System.out.println("玩游戏"+i);
    			if( i == 10){
    				Runnable t = new MusicRunnable();        //启动线程必须用线程类对象调用start();
    				new Thread(t).start();             //类Thread的一个构造器中Thread(Runnable target)分配新的 Thread 对象。
    			}
    		}
    	}
    }
    
    

    对比两种方法(吃苹果比赛)

    1、继承Thread类

    /**
     * 	案例:存在50个苹果,现在有请三个童鞋(小A,小B,小C)上台表演吃苹果.
     * 		因为A,B,C三个人可以同时吃苹果,此时得使用多线程技术来实现这个案例.
     *
     *       此处程序不合理,ABC每个线程都执行50次,即ABC每个人都吃一次编号50的苹果
     */
    class Person extends Thread{
    	private  int num= 50;
    	Person(String name){
    		super(name);
    	}
    	public void run() {
    		for(int i = 0;i < 50;i++){
    		if(num > 0)	
    		System.out.println(super.getName()+"吃了第"+num--+"个苹果");
    		}
    	}	
    }
    //使用继承Thread的方式创建线程
    public class ExtendsDemo {
    	public static void main(String[] args){
    		Person p1 = new Person("A");
    		p1.start();
    		Person p2 = new Person("B");
    		p2.start();
    		Person p3 = new Person("C");
    		p3.start();
    	}
    }
    
    

    2、实现Runnable接口

    class Apple implements Runnable{
    	private int num = 50;
    	public void run(){
    		for(int i = 0; i< 50 ;i++){
    			if(num > 0){
    				System.out.println(Thread.currentThread().getName()+"吃了第"+num--+"个苹果");
    			}//Thread.currentThread()   返回对当前正在执行的线程对象的引用。
    		}
    	}
    }
    //使用实现Runnable接口的方式,这种方法可以解决此问题
    public class ImplementsDemo {
    	public static void main(String[] args){
    		Runnable r = new Apple();
    		new Thread(r,"A").start();
    		new Thread(r,"B").start();
    		new Thread(r,"C").start();
    	}
    }
    
    

    对比

    继承方式:

    • java中类是单继承的,如果继承了Thread,该类就不能再有其他的直接父类
    • 从操作上分析,继承方式更简单,获取线程的名字也简单(操作上,简单)
    • 从多线程共享一个资源上分析,继承方式不能做到

    实现方式

    • java中类可以实现接口,此时该类还可以继承其他类,并且可以实现接口(设计上,更优雅)
    • 从操作上分析,实现方式稍微复杂点,获取线程的名字比较复杂,得使用currentThread()获取当前线程的引用。
    • 从多线程共享一个资源上分析,实现方式可以做到
  • 相关阅读:
    数据结构与算法之PHP实现二叉树的遍历
    数据结构与算法之二叉树的基本概念和类型
    聚集索引,非聚集索引,覆盖索引 原理
    Vue学习笔记:methods、computed、watch的区别
    xsl 和xml transform方法的调用
    Chrome , Firfox 不支持fireEvent的方法
    分布式存储
    firefox并不支持selectSingleNode和selectNodes的解决方法
    503 Service Unavailable
    处理【由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面】
  • 原文地址:https://www.cnblogs.com/tfper/p/9689916.html
Copyright © 2020-2023  润新知