java基础 day16---多线程

1.什么是进程
概念:正在运行的程序,是系统进行资源分配的基本单位。
目前的操作系统都是支持多进程的,可以同时执行多个进程,通过进程ID区分
2.什么是线程
概念:线程,又称轻量级进程,是进程中的一条执行路径,也是CPU的基本调度单位。
一个进程由一个或多个线程组成,彼此间完成不同的工作,同时执行,称为多线程。
宏观上是并行执行,微观上是串行的(电脑是单核的,微观上是串行的;如果电脑是多核的,其实真正实现了并行执行)。

3.进程和线程的区别

  1. 进程是操作系统资源分配的基本单位,而线程是CPU的基本调度单位
  2. 一个程序运行后至少包含一个进程
  3. 一个进程可以包含多个线程,但是至少需要有一个线程,否则这个进程就没有意义。
  4. 进程之间不能共享数据段地址,但同进程的线程之间可以

4.线程的组成

  1. CPU时间片:操作系统 OS会为每个线程分配执行时间
  2. 运行数据:(1)堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象
    (2)栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈
  3. 线程的逻辑代码

5.线程的特点

  1. 线程抢占式执行(效率高;可防止单一线程长时间独占CPU)
  2. 在单核CPU中,宏观上同时执行,微观上顺序执行

6、创建线程

  1. 继承Thread类
//创建线程的第一种方式:继承Thread类
public class MyThread extends Thread{
	
	//1.继承Thread类
	//2.重写run方法
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
		//this.getId()获取线程的id   this.getName()获取线程的名字(只能在继承Thread类下才可以用)
		System.out.println("线程id:"+this.getId()+"线程名称:"+this.getName()+"子线程-------"+i);
	//或者用下面这行代码也是一样的(不继承Thread类也可以用)【建议用这种方式,因为不继承Thread类也可以用】
	//System.out.println("线程id:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName());
		}
	}

}
public static void main(String[] args) {
		
		//3.创建对象
		MyThread myThread=new MyThread();
		
		//修改线程名称
		myThread.setName("我的子线程1");
		
		//4.调用start()方法,启动线程
		myThread.start();
		
		MyThread myThread2=new MyThread();
		myThread2.start();
		
		for(int i=0;i<100;i++) {
			System.out.println("主线程---"+i);
		}
/**
*抢占式执行,每一次运行结果都不一样
*/
	}

步骤总结:

(1)继承Thread类
(2) 重写run方法
(3)在main方法中创建对象
(4)调用start()方法,启动线程
  1. 实现Runnable接口
/**
 * 创建线程的第二种方式:实现Runnable接口
 * @author 1
 *
 */
public class MyRunnable implements Runnable{
	//1.实现Runnable接口
	//2.重写run方法
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			//这里就不能使用this.getId(),因为没有继承Thread类
			System.out.println("线程id:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()+".........."+i);
		}
		
	}

}

public static void main(String[] args) {
		
		//3.创建Runnable对象
		MyRunnable mr=new MyRunnable();
		//4.创建线程对象
		Thread thread=new Thread(mr, "我的子线程1");
		//5.调用start()
		thread.start();
		
		
		for(int i=0;i<100;i++) {
			System.out.println("main"+"---------------"+i);
		}

	}
//优化代码(使用了匿名内部类)
		Runnable runnable=new Runnable() {

			public void run() {
				for(int i=0;i<10;i++) {
					//这里就不能使用this.getId(),因为没有继承Thread类
					System.out.println("线程id:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()+".........."+i);
				}
			
		}

		};
		
		//创建线程对象
		Thread thread=new Thread(runnable, "我的子线程");
		
		//启动线程
		thread.start();

7.线程的基本状态

  1. 初始状态:线程对象被创建,即为初始状态,只在堆中开辟内存,与常规对象无异
  2. 就绪状态:调用start方法之后,进入就绪状态。等到OS选中,并分配时间片
  3. 运行状态:获得时间片之后,进入运行状态,如果时间片到期,则回到就绪状态
  4. 终止状态:主线程main()或独立线程run()结束,进入终止状态,并释放持有的时间片

8.线程的常见方法

  1. 休眠:(当前线程主动休眠xx毫秒)

Thread.sleep();//参数的单位是毫秒

  1. 放弃:(当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片)
    Thread.yield();

  2. 加入:(允许其他线程加入到当前线程中,并阻塞当前线程,直到加入的线程执行完毕,当前线程才会继续执行)

对象.join();

  1. 优先级(线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多)
    线程对象.setPriority();

9.同步方式

  1. 同步代码块:
	synchronized (this) {//共享资源必须是引用类型
						if(ticket<=0) {
							break;
						}
						System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票");
						ticket--;
					}

案例:

package com.hp.runnable;
/**
 * 实现4个窗口共卖100张票
 * @author 15163095307
 *
 */
public class SellTickets {
	public static void main(String[] args) {
		
		//1.创建Runnable对象
		Runnable runnable=new Runnable() {
			private int ticket=100;
			
//			Object obj=new Object();
			@Override
			public void run() {
				while(true) {
					synchronized (this) {//共享资源必须是引用类型
						if(ticket<=0) {
							break;
						}
						System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票");
						ticket--;
					}
				}
				
			}
			
		};
		
		//2.创建线程对象
		Thread thread=new Thread(runnable,"窗口1");
		Thread thread1=new Thread(runnable,"窗口2");
		Thread thread2=new Thread(runnable,"窗口3");
		Thread thread3=new Thread(runnable,"窗口4");
		//3.启动线程
		thread.start();
		thread1.start();
		thread2.start();
		thread3.start();
	}

}

  1. 同步方法
    在方法返回值类型前面加上synchornized
public synchornized boolean sale(){
	if(ticket<=0) {
							break;
						}
						System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票");
						ticket--;
	}

案例:

package com.hp.runnable;

public class Sale {
	
	
	/**
	 * 实现4个窗口共卖100张票
	 * @author 15163095307
	 *
	 */
	private static int ticket=100;
	
		public static void main(String[] args) {
			
			//1.创建Runnable对象
			Runnable runnable=new Runnable() {
			
				
//				Object obj=new Object();
				@Override
				public void run() {
					while(true) {
						if(!sale()) {
							break;
						}
							
						}
					}
					
				
				
			};
			
			
			
			//2.创建线程对象
			Thread thread=new Thread(runnable,"窗口1");
			Thread thread1=new Thread(runnable,"窗口2");
			Thread thread2=new Thread(runnable,"窗口3");
			Thread thread3=new Thread(runnable,"窗口4");
			//3.启动线程
			thread.start();
			thread1.start();
			thread2.start();
			thread3.start();
		}
		
		public  synchronized static boolean sale() {
			if(ticket<=0) {
				return false;
			}
			System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票");
			ticket--;
			return true;
		}

	}



10.线程池
为什么会有线程池的概念呢?
线程是宝贵的内存资源,单个线程约占1MB的空间,过多分配易造成内存溢出;
频繁的创建以及销毁线程会增加虚拟机回收频率,资源开销,造成程序性能的下降。

  1. 线程池:线程容器,可设定线程分配的数量上限;将预先创建的线程对象存入池中,并重用线程池中的线程对象;避免频繁的创建和销毁
  2. 线程池的原理:将任务交给线程池,由线程池分配线程,运行任务,并在当前任务结束后复用线程(比如一个线程池中有三个预先创建的线程,外边有4个任务执行,那么此时会随机选择三个任务,三个线程对象分别执行任务,剩下的那个任务等待,直到某个线程执行完某个任务,那么等待的任务再被执行,这就实现了线程的复用)
package com.hp.xianchengchi;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示线程池的创建
 * Executor:线程池的根接口,execute()
 * 
 * ExecutorService:包含了管理线程池的一些方法,比如submit  shutdown
 * 
 * Executors:创建线程池的工具类
 * 	(1)创建固定线程个数线程池
 * 	(2)创建缓存线程池,由任务的多少来决定,个数不固定
 * 	(3)创建单线程池
 * 	(4)创建调度线程池  调度:周期,定时执行
 * @author 1
 *
 */
public class Demo1 {
	public static void main(String[] args) {
		
		//1.创建固定线程个数线程池
//		ExecutorService es = Executors.newFixedThreadPool(4);
		//1.1创建缓冲线程池,线程个数是由任务的个数来决定的
		ExecutorService es= Executors.newCachedThreadPool();
		//2.创建任务
		Runnable runnable=new Runnable() {
			private int tickets=100;
			@Override
			public void run() {
			while(true) {
				if(tickets<=0) {
					break;
				}
				System.out.println(Thread.currentThread().getName()+"卖了"+tickets+"票");
				tickets--;
			}
				
			}
		};
		for(int i=1;i<=4;i++) {
			//3.提交任务
			es.submit(runnable);
		}
		
		//4.关闭线程池
		es.shutdown();//等待所有任务执行完毕,然后关闭线程池
		
		
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值