线程基础

基本概念

基本:

  • 程序:一段静态代码,静态对象
  • 进程:程序的一次执行过程
  • 线程:进程内部一个执行路径
    比如:QQ正在运行是一个进程,同时聊天,视频 两个线程

何时需要多线程:

  • 程序需要执行多个任务
  • 执行等待的任务:如搜索时需要等待服务器返回响应,等待时间让CPU做别的事情,先让这个程序占有的CPU做别的事情
  • 后台运行程序:在主程序的执行过程中,中途有一行代码开启了线程,当其中的主程序运行的代码和线程代码并行执行,则主程序代码和线程代码就不想关了

多线程的建立与启动

thread类(1)的:

  • 特性run() :线程体:代码写在run()方法中
  • start():用来启动线程
  • 异步性:
    • 两个线程各自保持前进的速度,你执行一次,我执行一次,接着我执行或者你执行,按照不同的顺序推进

创建线程的两种方式:

继承Thread类:
  1. 创建一个子类继承thread类

  2. 子类重写run方法

  3. 创建子类对象:即创建了线程对象

  4. 调用对象的start方法

    public class Test {
    public static void main(String[] args) {
    //3步:创建多线程对象
    Thread t=new ThreadTest();
    t.start();
    //4步:调用start方法,启动线程,调用run方法
    //threadTest.start();

     System.out.println("==========");
     System.out.println("=======5===");
     System.out.println("==========");
    

    }
    }

    /**创建一个子类继承thread类

    • 多线程:继承thread创建多线程
    • @author douer

    */
    public class ThreadTest extends Thread{
    //1.重写thread
    @Override
    public void run() {
    System.out.println(“多线程运行代码”);
    for(int i=0;i<3;i++) {
    System.out.println(i+6);
    System.out.println(i+6);
    }
    }
    }

实现接口Runnable:

  1. 定义子类实现runnable接口
    子类重写run方法
    public class RunableTest implements Runnable {
    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+" : 多线程运行代码");

  2. 在test中通过thread类含餐构造创建线程方法
    Thread t2=new Thread(new RunableTest(), “t-2 :”);//参数1是new一个实例,参数2是线程的名字

  3. start开启线程

  • Thread.currentThread().getName():获取当前线程的名称

  • 线程名称的作用:多线程运行时,可以明确是具体哪个的线程在运行
    实现接口:
    package ThreadTest;
    /**
    * 实现runnable接口的方式创建多线程
    * @author douer
    *
    */
    public class RunableTest implements Runnable {

    	@Override
    	public void run() {
    		System.out.println(Thread.currentThread().getName()+"  : 多线程运行代码");
    		for(int i=0;i<3;i++) {
    			System.out.println(Thread.currentThread().getName()+"==="+i);
    		
    	    }
    	
       }
    }
    

    Test运行:
    package ThreadTest;

    public class Test {
        public static void main(String[] args) {
    	//第二种Runnable方
        	//2步:通过thread
             Thread t2=new Thread(new RunableTest(), "t-2  :");//参数1是new一个实例,参数2是线程的名字
             t2.start();
             //作用:多线程运行时,可以明确是具体哪个的线程在运行
             Thread t3=new Thread(new RunableTest(), "t-3  :");
             
             
             t3.start();
    	System.out.println("=======1==");
    	System.out.println("=======5===");
    	System.out.println("=======7==");
    	
    }
    }
    

两者联系and区别:

  • 区别:

  • 常用接口方式来实现多线程:好处:

    1. 避免单继承的局限:‘
      子类可以实现多个接口,但是继承只能继承一个。比如student同时实现多线程,同时,又实现person的接口
    2. 共享同一个接口的对象==从而共同处理一份资源
      ex:
      • 两个线程共同增加count 数值

      • 两个线程共享同一个对象
        /new 同一个对象
        RunableTest r=new RunableTest();
        //参数r,被两个线程共享
        Thread t2=new Thread(r, “t-2 :”);
        t2.start();
        //作用:多线程运行时,可以明确是具体哪个的线程在运行
        Thread t3=new Thread(r, “t-3 :”);
        t3.start();
        两个线程同时对count进行++
        public class RunableTest implements Runnable {

         int count=0;
         @Override
         public void run() {
         	//System.out.println(Thread.currentThread().getName()+"  : 多线程运行代码"+count);
         	for(int i=0;i<3;i++) {
         		//System.out.println(Thread.currentThread().getName()+"==="+i);
         		count++;
         		System.out.println(Thread.currentThread().getName()+"  : 多线程运行代码"+count);
         	
             }
         
         }
        

        }

多线程优点

  1. 提高应用程序的响应
  2. CPU的利用率
  3. 改善程序结构:一个程序可以分成多个线程并行运行

thread类(2)的方法

  • join()阻塞:
    专业说法:阻塞当前的main方法,先不执行System.out.println("=====5=");
    先执行jion进来的代码,jion的线程执行全部完毕之后继续执行之前main阻塞的代码
    RunableTest r=new RunableTest();
    Thread t2=new Thread(r, “t-2 :”);
    t2.start();
    Thread t3=new Thread(r, “t-3 :”);
    t3.start();

    	System.out.println("=======1==");
    	//把t2的run()方法添加到main中执行,
    	//执行顺序一定是t2中的run一定在1与5之间
    	t2.join(); 
    	System.out.println("=======5===");
    	System.out.println("=======7==");
    
  • yield():线程让步
    暂停现在执行的程序,

  • sleep():睡眠
    Thread.sleep(1000);
    在实现线程的run中调用; 单位是毫秒
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

  • stop():强制停止线程声明周期
    RunableTest r=new RunableTest();
    Thread t2=new Thread(r, “t-2 :”);
    t2.start();
    Thread t3=new Thread(r, “t-3 :”);
    t3.start();

    	System.out.println("=======1==");
    	System.out.println(t2.isAlive());//确认还活着
    	
    	 t2.stop();//在这句话之前t-2可以执行,之后就不能执行
    	System.out.println("=======5===");
    	t3.join();
    	System.out.println("=======7==");
    

    t-2只执行了一次就消失了

  • boolean isAlive():判断当前线程是否还存活

线程生命周期

  1. 新建:创建线程实例
  2. 就绪:执行了start()方法之后,进入队列等待CPU的时间片
  3. 运行:run()方法开始执行
  4. 阻塞:run()被卡住
  5. 死亡:强制死亡stop();自然死亡;断电;杀掉进程

线程死锁

  • 成因:不同的线程占用需要的同步资源不放手,相互等待对方释放自己需要的同步资源
  • 解决方法:合理安排执行顺序;如:加锁顺序一致

线程通信

  • wait():挂起线程==阻塞

  • notify():唤醒排队中的最高级线程

  • notifyAll():唤醒所有线程
    //案例:实现:支付宝永远先执行,如果微信想先执行,则阻塞他
    使用this:
    public synchronized void drawing8(int m) throws Exception {
    String name=Thread.currentThread().getName();

    		if(name.equals("微信")) {
    			this.wait(); //当前对象阻塞
    		}
    		//取钱数目超过余额
    		if(money<m) {
    			System.out.println(name+"操作:账户金额不足,余额为:"+money);
    		}else {
    			System.out.println(name+"操作:账户原有金额:"+money);
    			money-=m;
    			System.out.println(name+"操作:账户提款金额:"+m);
    			System.out.println(name+"操作:账户提款之后金额:"+money);
    		}
    		if(name.equals("支付宝")) {
    			this.notify(); //唤醒当前最高优先级线程,处于就绪状态
    		}
    	}
    

生产者消费者问题

P V原理的实现

package ThreadTest;
/**
 * 生产者消费者:
 *  
 * @author douer
 *
 */
/*
 * 1.生产者生产的时候不消费,消费时不是生产
 * 2. 产品数为0开始生产,产品>5则停止生产
 * 3.产品数==5则开始消费,直到全部消费完成
 */
public class Test4 {
	public static void main(String[] args) {

		
		Clerk c=new Clerk();
		
		//生产者
		//创建一个线程
		//使用匿名类创建一个线程
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				//加锁
				synchronized(c) {
					//无限循环:跳出条件在里面
					while(true) {//考试时以为这个没用呢
						//产品数为0开始生产;直到到达一定数额
						if(c.productNum==0) {
							System.out.println("=====开始生产:"+c.productNum);
							while(c.productNum<4) {
								System.out.println("目前库存:"+c.productNum++);
							}
			                //生产完毕则跳出循环
							System.out.println("====生产完毕::::"+c.productNum);
							//生产完毕之后唤醒消费进程
							c.notify();
						}
						//产品还有,不生产,进程阻塞
						else {
							try {
								c.wait();
							} catch (Exception e) {
								
								e.printStackTrace();
							}
						}
						
						
					}
					
				}
				
			}
		}, "生产者").start();

	
	//消费者
        new Thread(new Runnable() {
		
		@Override
		public void run() {
			//加锁
			synchronized(c) {
				//无限循环:跳出条件在里面
				while(true) {
					//产品数为0开始生产;直到到达一定数额
					if(c.productNum==4) {
						System.out.println("=====开始消费哦:"+c.productNum);
						while(c.productNum>0) {
							System.out.println("目前库存:"+c.productNum--);
						}
		                //生产完毕则跳出循环
						System.out.println("====消费完毕::::"+c.productNum);
						c.notify();
					}
					//产品还有,不生产,进程阻塞
					else {
						try {
							c.wait();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					
				}
				
			}
			
		}
	}, "生产者").start();
	
	
	//
//	producer.start();
//	consum.start();
}
	
	
}
class Clerk{
	public  static int  productNum=0;
}
发布了15 篇原创文章 · 获赞 7 · 访问量 4175
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章