• Java多线程的创建与简单使用


    一、线程的基本概念

    什么是线程:Thread

    • 进程内部的一个执行单元,它是程序中一个单一的顺序控制流程。
    • 线程又被称为轻量级进程(lightweight process)
    • 如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为多线程

    通俗来讲,在程序中新建一共线程,就好像在程序中新开辟一条道路

    二、创建线程的三种方法

    1.继承Thread类

      我们新创建的类可以继承Thread类,并且重写Run方法来实现我们想要的方法,并且通过start()方法来启动这一个线程。

    示例如下:

    package top.dlkkill.th;
    
    public class MyThread extends Thread{
    	
    	private String name;
    	
    	public MyThread(String name) {
    		super();
    		this.name = name;
    	}
    	public MyThread() {
    		
    	}
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		for(int i=0;i<20;i++) {
    			System.out.println(name+" : "+i);
    		}
    	}
    	
    }
    //使用如下方式来启动两个线程
    public static void test1() {
    		MyThread th1=new MyThread("th1");
    		MyThread th2=new MyThread("th2");
    		th1.start();
    		th2.start();
    		return;
    	}
    

      这是创建一共线程最简单的方式,但是有很大的约束,因为在Java中的是单继承的,所以一共类只能继承自另外一个类,所以如果要使用这种方法,就必须使得我们的类要Thread类才可以,这样就使得程序很不灵活,有很大的限制。这样我们就引入了第二种方法。

    2.实现Runnable接口(静态代理模式)

    1)什么是静态代理模式

    代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如上图所示:

    • 抽象主题角色:可以是接口,也可以是抽象类;
    • 委托类角色:真实主题角色,业务逻辑的具体执行者;
    • 代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

    引自:https://blog.csdn.net/justloveyou_/article/details/79407248

    而静态代理模式是指在程序运行前由程序员提前写好固定的代码(与之相对的是动态代理模式)

    代理模式简单说就是讲自己的事物委托给代理人,由代理人去处理事物开始,运行,结束的事情。

    静态代理模式的实现要求:

    1. 真实角色
    2. 代理角色(持有对真实角色的引用)
    3. 二者实现相同的接口

    静态代理模式的实现过程:

    1. 创建真实角色
    2. 创建代理角色+真实角色引用
    3. 执行任务

    假设我们由一个人要结婚(真实角色),委托给婚庆公司(代理角色),抽象主题就是结婚

    代码如下:

    package top.dlkkill.th;
    
    public class Example {
    	public static void main(String[] args) {
    		MarryPeople peo=new MarryPeople();
    		MarryConpany conp=new MarryConpany(peo);
    		conp.marry();
    	}
    	
    }
    
    interface Marry{
    	public void marry();
    }
    class MarryPeople implements Marry{
    	@Override
    	public void marry() {
    		// TODO Auto-generated method stub
    		System.out.println("People Marry");
    	}
    }
    class MarryConpany implements Marry{
    	private MarryPeople peo;
    	public MarryConpany(MarryPeople peo) {
    		super();
    		this.peo = peo;
    	}
    	@Override
    	public void marry() {
    		// TODO Auto-generated method stub
    		before();
    		peo.marry();
    		after();
    	}
    	public void before() {
    		System.out.println("准备工作");
    	}
    	public void after() {
    		System.out.println("收尾工作");
    	}
    }
    

    2)Runable创建线程

    优点:

    1. 避免单继承的局限性
    2. 便于共享资源

    实现过程如下:

    package top.dlkkill.th;
    
    public class MyThread2 implements Runnable{
    	private String name;
    	private boolean flag=true;
    	private int num=50;
    	public void setFlag(boolean flag) {
    		this.flag = flag;
    	}
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		while(num>0) {
    			System.out.println(Thread.currentThread().getName()+"抢到----->"+num--);
    		}
    		//System.out.println(name+"------->Stop");
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public MyThread2(String name) {
    		super();
    		this.name = name;
    	}
    	public MyThread2() {
    		super();
    		// TODO Auto-generated constructor stub
    	}
    	public static void test2() throws InterruptedException {
    		MyThread2 myth1=new MyThread2("th1");
    		MyThread2 myth2=new MyThread2("th2");
    		Thread th1=new Thread(myth1,"路人甲");
    		Thread th2=new Thread(myth2,"路人乙");
    		th1.start();
    		th2.start();
    		Thread.sleep(100);
    		myth1.setFlag(false);
    		myth2.setFlag(false);
    		return;
    	}
    }
    
    

    这里我们假设一共50张票,路人甲和路人乙进行抢票。
    我们创建了两个线程,但是都共享50张票的资源,当50张票抢完后,两个线程自动结束。

    3.实现Callable<V>接口

    这种方法的优点是我们可以抛出我们想要的异常进行异常处理,另外可以得到返回值
    但是这种方法的实现过程稍显复杂。

    示例如下:

    package top.dlkkill.th;
    
    import java.util.concurrent.Callable;
    
    public class MyThread3 implements Callable<Integer> {
    	@Override
    	public Integer call() throws Exception {
    		// TODO Auto-generated method stub
    		for(int i=0;i<300;i++)
    			continue;
    		return 300;
    	}
        public static void test3() throws InterruptedException, ExecutionException {
            //创建一个线程
    		ExecutorService exe=Executors.newFixedThreadPool(1);
    		MyThread3 th=new MyThread3();
            //得到返回值
    		Future<Integer> restult=exe.submit(th);
    		int num=restult.get();
    		System.out.println(num);
            //结束线程
    		exe.shutdownNow();
    		return;
    	}
    }
    
    

    三、线程的状态与终止

    1.状态

    2.线程的终止

    线程的终止有两种情况:

    1. 自然终止:线程体正常执行完毕
    2. 外部干涉:
      • 线程类中 定义 线程体使用的标识
      • 线程体使用该标识
      • 提供对外的方法改变该标识
      • 外部根据条件调用该方法即可

    实例如下:

    package top.dlkkill.th;
    
    public class MyThread2 implements Runnable{
    	private String name;
    	private boolean flag=true;
    	private int num=50;
    	public void setFlag(boolean flag) {
    		this.flag = flag;
    	}
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		while(flag) {
    			//System.out.println(Thread.currentThread().getName()+"抢到----->"+num--);
    			System.out.println(name+"----->run");
    		}
    		System.out.println(name+"------->Stop");
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public MyThread2(String name) {
    		super();
    		this.name = name;
    	}
    	public MyThread2() {
    		super();
    		// TODO Auto-generated constructor stub
    	}
    	public static void test2() throws InterruptedException {
    		MyThread2 myth1=new MyThread2("th1");
    		MyThread2 myth2=new MyThread2("th2");
    		Thread th1=new Thread(myth1,"路人甲");
    		Thread th2=new Thread(myth2,"路人乙");
    		th1.start();
    		th2.start();
    		Thread.sleep(100);
            //标识改变后,线程结束
    		myth1.setFlag(false);
    		myth2.setFlag(false);
    		return;
    	}
    	
    }
    
    
  • 相关阅读:
    DEVMODE 结构体
    VS2019如何将主菜单从标题栏移到单独一行
    最近学到的东西
    线上问题处理相关思考
    mybatis+spring
    jenkins
    自动化case校验点
    Sqlserver大数据迁移,导出-》导入(BULK INSERT)
    阿里P7大佬带你解密Sentinel
    《高可用系列》-限流神器Sentinel,不了解一下吗?
  • 原文地址:https://www.cnblogs.com/DLKKILL/p/10368908.html
Copyright © 2020-2023  润新知