zoukankan      html  css  js  c++  java
  • 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方法并不意味着立即执行多线程代码,而是使得线程变为可运行状态。

  • 相关阅读:
    day 66 ORM django 简介
    day 65 HTTP协议 Web框架的原理 服务器程序和应用程序
    jQuery的事件绑定和解绑 事件委托 轮播实现 jQuery的ajax jQuery补充
    background 超链接导航栏案例 定位
    继承性和层叠性 权重 盒模型 padding(内边距) border(边框) margin 标准文档流 块级元素和行内元素
    属性选择器 伪类选择器 伪元素选择器 浮动
    css的导入方式 基础选择器 高级选择器
    03-body标签中相关标签
    Java使用内存映射实现大文件的上传
    正则表达式
  • 原文地址:https://www.cnblogs.com/yn-yinian/p/7788405.html
Copyright © 2011-2022 走看看