• JAVA-多线程


    进程:正在进行中的程序

    线程:就是进程中一个负责程序执行的控制单元(执行路径。)

    一个进程中可以有多条执行路径,称为多线程。(比如,360软件,可同时杀毒,体检,清理垃圾等等,每一个功能相当于一条执行路径,同时执行,执行多条路径,也就是多线程了)。

    也就是说,当我们想让多部分代码同时执行的时候,就是多线程了。每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。

    好处与弊端:

    好处:解决了多部分同时运行的问题,充分利用CPU资源,简化编程模型,带来良好的用户体验。

    弊端:线程太多回到效率的降低。

    其实应用程序的执行都是cpu在做着快速的切换完成的,这个切换时随机的。

    类 Thread:

    主线程:

    main()方法即为主线程入口

    产生其他子线程的线程

    必须最后完成执行,因为它执行各种关闭动作

    Thread td = Thread.currentThread();
    System.out.println("当前线程是:"+td.getName());
    td.setName("萌萌");
    System.out.println("当前线程是:"+td.getName());
    

    运行结果:

    当前线程是:main
    当前线程是:萌萌
    

    在java中实现多线程的两种方式:

    继承Thread类,实现Runnable接口。

    class MyThread implements Runnable
    class MyRunnable implements Runnable
    

    Thread类构造方法:

    Thread类常用方法:

    start(); 启动线程
    getId(); 获得线程ID
    getName(); 获得线程名字
    getPriority(); 获得优先权
    isAlive(); 判断线程是否活动
    isDaemon(); 判断是否守护线程
    getState(); 获得线程状态
    sleep(long mill); 休眠线程
    join(); 等待线程结束
    yield(); 放弃cpu使用权利
    interrupt(); 中断线程
    currentThread(); 获得正在执行的线程对象

    Runnable接口:

    Runnable接口方法:

     

    run()方法和start()方法的区别:

    Tread类中start()方法是开始线程的方法。start()方法会用特殊的方法自动调用run()方法。run()方法是Tread的具体实现。
    继承了Thread类后就通过重写run()方法来说明线程的行为,调用start()方法来开始线程。

    小示例:这里使用了JUNIT测试类,java里自带的,省略了main方法

    public class Demo {
    	@Test
    	public void test1(){
    		MyThread t1 = new MyThread();
    		Thread td = new Thread(t1);
    		td.start();
    	}
    }
    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			String name = Thread.currentThread().getName();
    			System.out.println(name+":"+i);
    		}
    		System.out.println("结束~");
    	}
    }
    

    输出结果:这个输出结果每次都不一样,多线程是随机的。

    Thread-0:0
    Thread-0:1
    Thread-0:2
    Thread-0:3
    Thread-0:4
    Thread-0:5
    Thread-0:6
    Thread-0:7
    Thread-0:8
    Thread-0:9
    Thread-0:10
    Thread-0:11
    Thread-0:12
    Thread-0:13
    Thread-0:14
    Thread-0:15
    Thread-0:16
    Thread-0:17
    Thread-0:18
    Thread-0:19
    Thread-0:20
    Thread-0:21
    Thread-0:22
    Thread-0:23
    Thread-0:24
    Thread-0:25
    Thread-0:26
    Thread-0:27
    Thread-0:28
    Thread-0:29
    Thread-0:30
    Thread-0:31
    Thread-0:32
    Thread-0:33
    Thread-0:34
    Thread-0:35
    Thread-0:36
    Thread-0:37
    Thread-0:38
    Thread-0:39
    Thread-0:40
    Thread-0:41
    Thread-0:42
    Thread-0:43
    

    小修改一下:

    public class Demo {
    	@Test
    	public void test1(){
    		MyThread t1 = new MyThread();
    		Thread td1 = new Thread(t1,"线程1");
    		Thread td2= new Thread(t1,"线程2");
    		td1.start();
    		td2.start();
    	}
    }
    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			String name = Thread.currentThread().getName();
    			System.out.println(name+":"+i);
    		}
    		System.out.println("结束~");
    	}
    }
    

    部分输出结果:随机的

    线程1:45
    线程1:46
    线程1:47
    线程2:0
    线程1:48
    线程2:1
    线程1:49
    线程2:2
    线程1:50
    线程2:3
    线程1:51
    线程2:4
    线程1:52
    线程2:5
    线程1:53
    线程2:6
    线程1:54
    线程2:7
    线程1:55
    线程2:8
    线程1:56
    

    线程的状态(五个):创建、就绪、阻塞、运行、死亡。

    线程调度:线程带的优先级1-10表示,1表示优先级最低,10表示优先级最高,默认是5。这些优先级对象一个Thread类的公用静态变量。

    public static final int NORM_PRIORITY = 5;
    public static final int MAX_PRIORITY = 10;
    public static final int MIN_PRIORITY = 1;
    

    优先级示例:

    public class Demo {
    	@Test
    	public void test1(){
    		MyThread t1 = new MyThread();
    		Thread td1 = new Thread(t1,"线程1");
    		Thread td2= new Thread(t1,"线程2");
    		
    		System.out.println(td1.getPriority());//获取优先级
    		System.out.println(td2.getPriority());
    		td1.start();
    		td2.start();
    	}
    }
    
    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			String name = Thread.currentThread().getName();
    			System.out.println(name+":"+i);
    		}
    		System.out.println("结束~");
    	}
    }
    

    输出结果,优先级默认都是5:

    5
    5
    线程1:0
    线程1:1
    线程1:2
    线程1:3
    线程1:4
    线程1:5
    线程1:6
    线程1:7
    线程1:8
    线程1:9
    线程1:10
    线程2:0
    线程1:11
    线程2:1
    线程1:12
    线程2:2
    线程1:13
    线程2:3
    线程1:14
    线程2:4
    线程1:15
    线程2:5
    线程1:16
    线程2:6
    线程1:17
    线程2:7
    线程1:18
    线程2:8
    线程1:19
    线程2:9
    线程1:20
    线程2:10
    线程1:21
    线程2:11
    线程1:22
    线程2:12
    线程1:23
    线程2:13
    线程1:24
    线程2:14
    线程1:25
    线程2:15
    线程1:26
    线程2:16
    线程1:27
    线程2:17
    线程1:28
    线程2:18
    线程2:19
    线程1:29
    线程2:20
    线程1:30
    线程2:21
    线程1:31
    线程2:22
    线程1:32
    线程2:23
    线程1:33
    

    小修改一下:

    public class Demo {
    	@Test
    	public void test1(){
    		MyThread t1 = new MyThread();
    		Thread td1 = new Thread(t1,"线程1");
    		Thread td2= new Thread(t1,"线程2");
    		
    		td1.setPriority(10);//指定优先级
    		td2.setPriority(1);
    		td1.start();
    		td2.start();
    	}
    }
    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			String name = Thread.currentThread().getName();
    			System.out.println(name+":"+i);
    		}
    		System.out.println("结束~");
    	}
    }
    

    输出结果,优先级10和1的区别:

    线程1:0
    线程1:1
    线程1:2
    线程1:3
    线程1:4
    线程1:5
    线程1:6
    线程1:7
    线程1:8
    线程1:9
    线程1:10
    线程1:11
    线程1:12
    线程1:13
    线程1:14
    线程1:15
    线程1:16
    线程1:17
    线程1:18
    线程1:19
    线程1:20
    线程1:21
    线程1:22
    线程1:23
    线程1:24
    线程1:25
    线程1:26
    线程1:27
    线程1:28
    线程1:29
    线程1:30
    线程1:31
    线程1:32
    线程1:33
    线程1:34
    线程1:35
    线程1:36
    线程1:37
    线程1:38
    线程1:39
    线程1:40
    线程1:41
    线程1:42
    线程1:43
    线程1:44
    线程1:45
    线程1:46
    线程1:47
    线程1:48
    线程1:49
    线程1:50
    线程1:51
    线程1:52
    线程1:53
    线程1:54
    线程1:55
    线程1:56
    线程1:57
    线程1:58
    线程1:59
    线程1:60
    线程1:61
    线程1:62
    线程1:63
    线程1:64
    线程1:65
    线程1:66
    线程1:67
    线程1:68
    线程1:69
    线程1:70
    线程1:71
    线程1:72
    线程1:73
    线程1:74
    线程1:75
    线程1:76
    线程1:77
    线程1:78
    线程1:79
    线程1:80
    线程1:81
    线程1:82
    线程1:83
    线程1:84
    线程1:85
    线程1:86
    线程1:87
    线程1:88
    线程1:89
    线程1:90
    线程1:91
    线程1:92
    线程1:93
    线程1:94
    线程1:95
    线程1:96
    线程1:97
    线程1:98
    线程1:99
    结束~
    线程2:0
    线程2:1
    线程2:2
    线程2:3
    

    线程的休眠,sleep():

    sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。

    sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;

    在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行。

    sleep()与wait()的比较:

    wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。

    而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态”。

    但是,wait()会释放对象的同步锁,而sleep()则不会释放锁。

    wait()可以指定时间也可以不指定时间。sleep()必须指定时间。

    在同步中,对CPU的执行权和锁的处理不同。

    wait:释放执行权,释放锁。

    sleep:释放执行权,不释放锁。

    线程的强制运行,join():

    与sleep()方法一样,调用join()方法需要处理InterruptedException异常。

    线程的礼让,yield():

    yield()方法可暂停当前线程执行,允许其他具有相同优先级的线程获得运行机会,该线程仍处于就绪状态,不转为阻塞状态,此时,系统选择其他相同或更高优先级线程执行,若无其他相同或更高优先级线程,则该线程继续执行。

    最后示例演示:

    public class Demo {
    	@Test
    	public void test1() throws InterruptedException{
    		PaShan ps = new PaShan();
    		Thread nqr = new Thread(ps,"年轻人");
    		Thread old = new Thread(ps,"老年人");
    		
    		nqr.start();
    		old.start();
    		
    		Thread.currentThread().join();//暂停主线程
    	}
    }
    class PaShan implements Runnable{
    	@Override
    	public void run() {
    		//得到当前线程的名称
    		String name = Thread.currentThread().getName();
    		for (int i = 1; i <= 10; i++) {
    			System.out.println(name+"爬完"+(i*100)+"米");
    			//加一个判断
    			if(name.equals("年轻人")){try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}}
    			else{try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}}
    		}
    		System.out.println(name+"爬到山顶了");
    	}
    }
    

    动态直观输出结果:

    线程同步的实现:

    当两个或多个线程需要访问同一资源时,需要以某种顺序来确保该资源某一时刻只能被一个线程使用,这就称为线程同步。

    采用线程同步来控制线程的执行有两种方式,即同步代码方法和同步代码块。这两种方式都使用synchronized关键字实现。

    1.同步方法

    使用synchronized修饰的方法控制对类成员变量的访问。每个类实例对应一把锁,方法一旦执行,就独占该锁,知道从该方法返回时才将锁释放,此后,被阻塞的线程方能获得该锁,重新进入可执行状态。

    示例:

    创建Site类:

    public class Site implements Runnable {
    	public int count = 10;//剩余票数
    	public int num = 0;//买到第几张票票
    	public boolean flag = false;
    	@Override
    	public void run() {
    		while(!flag){
    			sale();
    		}
    	}
    	public synchronized void sale(){
    			if(count<=0){
    				flag = true;
    				return;
    			}
    			num++;
    			count--;
    				try {
    					Thread.sleep(500);//模拟网络延迟
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			//第二步:显示信息
    			System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");
    		}
    	}
    

    创建测试类:

    public class MyTest {
    	public static void main(String[] args) {
    		Site site = new Site();
    		Thread p1 = new Thread(site,"普通人");
    		Thread p2 = new Thread(site,"代理");
    		Thread p3 = new Thread(site,"黄牛");
    		p1.start();
    		p2.start();
    		p3.start();
    	}
    }
    

    输出结果:

    普通人抢到第1张票,剩余9张票!
    普通人抢到第2张票,剩余8张票!
    普通人抢到第3张票,剩余7张票!
    黄牛抢到第4张票,剩余6张票!
    代理抢到第5张票,剩余5张票!
    黄牛抢到第6张票,剩余4张票!
    黄牛抢到第7张票,剩余3张票!
    普通人抢到第8张票,剩余2张票!
    普通人抢到第9张票,剩余1张票!
    普通人抢到第10张票,剩余0张票!
    

    2.同步代码块

    代码块即使用{}括起来的一段代码,使用synchronized关键字修饰的代码块,称为同步代码块。

    实际上实现多线程的方式还有一种:

    实现Callable接口,重写call方法。Callable接口与Runnable接口的功能类似,但提供了比Runnable更强大的功能。有以下三点
    (1)Callable可以在人物结束后提供一个返回值,Runnable没有提供这个功能。
    (2)Callable中的call方法可以抛出异常,而Runnable的run方法不能抛出异常。
    (3)运行Callable可以拿到一个Future对象,表示异步计算的结果,提供了检查计算是否完成的方法。

    需要注意的是,无论用那种方式实现了多线程,调用start方法并不意味着立即执行多线程代码,而是使得线程变为可运行状态。

  • 相关阅读:
    Swift_数据存储
    Swift_零碎知识
    Flutter安装与使用
    供热
    iOS_2022_动画
    依赖管理
    Swift_协议
    Swift_网络请求
    数据转换的使用
    Map相关、MapUtils、MultiMap、LazyMap、BidiMap
  • 原文地址:https://www.cnblogs.com/yn-yinian/p/7788405.html
Copyright © 2020-2023  润新知