多线程的理解与学习

-----------多线程-----------

什么是多线程???

  1. 多线程的概念:
    如果在一个进程中同时运行了多个线程,
    用来完成不同的工作,则称之为“多线程”
    多个线程交替占用CPU资源,而非真正的并行执行

  2. 多线程好处
    充分利用CPU的资源
    简化编程模型
    带来良好的用户体验

  3. 主线程
    main()方法即为主线程入口
    产生其他子线程的线程
    必须最后完成执行,因为它执行各种关闭动作

  4. 在Java中创建线程的两种方式
    继承java.lang.Thread类
    实现java.lang.Runnable接口

    使用线程的步骤:
    (1)定义线程
    (2)创建线程对象
    (3)启动线程
    (4)终止线程

  5. 继承Thread类创建线程
    步骤:
    定义MyThread类继承Thread类
    重写run()方法,编写线程执行体

     测试类中:
     	创建线程对象,调用start()方法启动线程
    
     public class Test11 {
     	public static void main(String[] args) {
     		MyThread mt1 = new MyThread();
     		MyThread mt2 = new MyThread();
     		mt1.start();
     		mt2.start();
     	}
     }
     class MyThread extends Thread{
     	@Override
     	public void run() {
     		for (int i = 1; i <=20; i++) {
     			System.out.println("你好 ,"+ Thread.currentThread().getName());
     		}
     	}
     }	
     
     直接结果分析:
     	多个线程交替执行,不是真正的“并行”
     	线程每次执行时长由分配的CPU时间片长度决定
     
     并行:	两个程序都执行,同时进行,抢占CPU资源。
     
     并发:  做完一件事,立马在做另一件事,称为并发。
    
  6. 启动线程调用 线程对象的start 方法,和run方法的区别。

     调用start()  :子线程执行run()方法
     				多条执行路径,主线程和子线程并行交替执行
     
     调用run()	:主线程执行run()
     				只有主线程一条执行路径
    
  7. 实现Runnable接口创建线程

     步骤:	
     	定义MyRunnable类实现Runnable接口
     	实现run()方法,编写线程执行体
     	测试类:
     		创建线程对象,调用start()方法启动线程
    
     public class Test3 {
     	public static void main(String[] args) {
     		MyRunnable mr = new MyRunnable();  //创建实现了线程接口的对象。
     		Thread t = new Thread(mr);	//创建线程对象,把线程接口对象传递
     		t.start();		//开启线程。
     	}
     }
     class MyRunnable implements Runnable{ //创建MyRunnable类,实现Runnable接口
     	@Override
     	public void run() {		//重写run方法
     		for (int i = 0; i <= 100; i++) {
     			System.out.println(Thread.currentThread().getName() +"---" + i);
     		}
     	}
     }
    
  8. 比较两种创建线程的方式

     继承Thread类
     	编写简单,可直接操作线程
     	适用于单继承
     
     实现Runnable接口
     	避免单继承局限性
     	便于共享资源	
     
     推荐使用实现Runnable接口方式创建线程
    
  9. 线程中,常见的线程调度方法:

    线程调度指按照特定机制为多个线程分配CPU的使用权
    
    setPriority(int  newPriority)	更改线程的优先级
    		线程优先级由1~10表示,1最低,默认优先级为5
    		优先级高的线程获得CPU资源的概率较大
    
    static void sleep(long millis)	在指定的毫秒数内让当前正在执行的线程休眠
    		让线程暂时睡眠指定时长,线程进入阻塞状态
    		睡眠时间过后线程会再进入可运行状态
    
    		millis为休眠时长,以毫秒为单位
    		调用sleep()方法需处理InterruptedException异常
    
    void join()	等待该线程终止
    		使当前线程暂停执行,等待其他线程结束后再继续执行本线程
    	
    		
    join(millis)
    		millis:以毫秒为单位的等待时长
    		nanos:要等待的附加纳秒时长
    		需处理InterruptedException异常
    
    
    static void yield()	暂停当前正在执行的线程对象,并执行其他线程
    		暂停当前线程,允许其他具有相同优先级的线程获得运行机会
    		该线程处于就绪状态,不转为阻塞状态
    
    void interrupt()	中断线程
    		
    boolean isAlive()	测试线程是否处于活动状态
    		
    Thread.currentThread()		获取当前线程对象
    
    获取线程名字,设置线程名字:
    	getName()   setName()
    
  10. 守护线程 setDaemon();

    守护线程,不会单独执行,

       	当被守护的线程执行完,
       	那么守护线程也就不再单独执行,发现了就结束。
    

    练习: 创建两个线程。

       	分别让两个线程执行循环输出。
       		A线程,循环5次。 (被守护线程)
       		
       		B线程,循环50次。(设置为守护线程)
    
  11. 实现代码同步的两种方式

(1)用同步代码块的形式实现。
		语法:
			synchronized(锁对象){
				希望被同步的代码;
			}
			
	锁对象: 可以是任何一个类的对象,但是不能是匿名对象。
			通常,可以用一个 this ,this 代表当前类对象。                                
			
			但是注意,如果多个线程子对象操作一个需要同步的代码块的时候
			this 不是同一个锁对象,所以不能产生同步效果
			
		
	常用的三种锁对象
		this  当前类对象。
		随便创建一个类的对象用。
		
		当前类的字节码对象,有且只有一个(推荐使用)
		
			
			
(2)  通过执行被synchronized 修饰的方法,来实现同步。

		在方法的权限修饰词后面 加上 synchronized 即可。

		
(3)  测试,验证,两种同步代码方式		
			其中同步方法用的锁对象是什么!!!
			经过测试,得出结论.
				: 同步方法,用的锁对象,是this
  1. 多线程共享数据的实现。
    变量,被static 修饰,进入常量池,就不会重复创建。
    这样几个子线程,即会共享该变量。

  2. 购票练习:

    定义一个购票类,100张票。

    测试类里面,创建四个线程,让他们抢票。

    每次抢票输出自己的线程名字,和剩余票数。

    public class Test22 {
    public static void main(String[] args) {
    Ticket2 t2 = new Ticket2();
    new Thread(t2,“张三售票口:”).start();
    new Thread(t2,“李四售票口:”).start();
    new Thread(t2,“王五售票口:”).start();
    new Thread(t2,“赵六售票口:”).start();
    }
    }

    class Ticket2 implements Runnable{ //定义售票窗口类,继承多线程,

       public static int tickets = 100;
       public void run(){		//重写run方法,里面的代码,在子线程中执行.
       	while(true){
       		//锁对象用,当前类的字节码对象的问题,创建完第一个字节码对象后,就不再创建了
       		synchronized (Ticket2.class) {  // this 可以不可以? 为什么?this不是同一个对象
       			if (tickets <= 0) { //由于线程不同步的问题,造成 可能会卖负票.
       				break;
       			}
       			try {
       				Thread.sleep(100);
       			} catch (InterruptedException e) {
       				e.printStackTrace();
       			}
       			System.out.println(Thread.currentThread().getName()
       					+ " 窗口,卖出第[" + tickets-- + "]火车票");
       		}
       	}	
       }
    

    }

  3. 多线程操作中,锁对象,产生死锁的问题。

    在多线程嵌套的 代码情况下,如果用了相同的锁对象
    那么就会出现互斥锁,也称死锁的问题。
    有可能无法同步。

    所以开发中,一定要注意使用锁对象,避免死锁问题出现。

  4. 单例模式

    通过封装一个方法。给你返回本类对象。
    	不让调用者来创建对象。
    
    好处: 这样这个类,创建的对象,是唯一的,谁要用,就给谁用。
    		大家不需要创建。
    

    实现单例的步骤:
    (1) 私有构造方法
    (2) 提供一个方法,创建本类对象,并返回。
    饿汉式 : 直接在类中的属性声明处,创建好对象,
    获取对象方法中,直接返回该对象。

    					获取对象的时候效率高,空间换时间。
    		 
    		 懒汉式 : 属性声明位置,先声明对象,不创建对象赋值。
    					获取对象的方法中,判断对象为null。再创建。
    					并返回。
    					
    					单例设计比较节省空间, 时间换空间。
    
    	public class Test4 {
    		public static void main(String[] args) {
    			Single s =Single.getInstance() ;
    		}
    	}
    
    	class Single {		//创建一个  单例类.  懒汉式.
    		
    		static Single s ;  //null
    		private Single(){}		//1 私有构造方法
    		//2 创建一个方法,对外提供本类对象.
    		public static Single getInstance(){
    			if (s ==null) {
    				s = new Single();
    			}
    			return s;
    		}
    	}
    	class Single2{		//饿汉式,创建单例类.
    		static final Single2 s2 = new Single2();  //被final修饰,唯一一个对象,不重复创建
    		private Single2(){}		//1 私有构造方法
    		
    		//2 创建一个方法,对外提供本类对象.
    		public static Single2 getInstance(){
    			return s2;
    		}
    	}
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值