17.线程

线程

进程:正在运行的程序

线程:程序运行过程中的一个小单元

例如:开门开窗户卖票到关窗户关门 结束卖票 进程 其中任意一个窗户可以实现一定任务 线程

关系:进程中 至少包含一个线程 线程一定属于某个进程

多线程配置:当执行多线程任务时 其实是CPU在各个线程中快速切换 时间非常短 感觉是在同时执行

例如:可以通过增加下载任务的线程 更多几率的获取CPU处理权限

CPU时间片段分配原则:

​ 1.分时调度:所有线程轮流使用CPU的使用权 平均分配给每个线程时间片段

​ 2.抢占式调度:优先级高的会大概率优先获取时间片段 如果优先级相同 则CPU随机选择线程执行

多核处理器:相当于在单核CPU切换中 让切换效率翻倍 并没有提高程序的运行速度 只是提升了CPU的利用率

java程序开启后 开始执行的线程有 主线程 同时开启GC线程(垃圾回收线程 守护线程)

线程优先级设定
设置线程优先级
线程对象.setPriority(Thread.MAX_PRIORITY);			10
线程对象.setPriority(Thread.MIN_PRIORITY);			1
线程对象.setPriority(Thread.NORM_PRIORITY);			5
查看线程优先级
SYSO(线程对象.getPriority());			
Thread 线程
	Thread.currentThread()//获取当前线程对象		
	System.out.println(Thread.currentThread().getName());//main 主线程

案例:

​ 一个人买100张票

​ 两个人 各自买各自的100张票

​ 两个人共同买100张票–》线程安全问题

方案一 继承自Thread类 重写run()
//案例二:每个用户有自己的100张票 并不会出现线程安全问题
public class Users extends Thread{
    int count = 100;
    public void run(){
        //线程任务
        while(count>0){
            syso(Thread.currentThread().getName()+"买到第"+(101-count)+"张票");
            count--;
        }
    }
}
//测试类main方法中
	Users u1 = new Users();
	u1.setName("张三");//给线程对象命名  若不起名 则默认名称效果:Thread-0  Thread-1..
	u1.start();//开启线程的必须方法  不能使用run()否则变为单线程普通方法调用效果

	Users u2 = new Users();
	u2.setName("李四");
	u2.start();
//案例三:每个用户共享100张票 会出现线程安全问题---》多个线程共同操作同一个数据 并且进行了数据更新
public class Users extends Thread{
    static int count = 100;
    public void run(){
        //线程任务
        while(count>0){
            syso(Thread.currentThread().getName()+"买到第"+(101-count)+"张票");
            count--;
        }
    }
}

练习:

​ 商店有10只猫 10只狗

​ 如果是张三来购买 买猫 每次一只 买完为止 如果是李四 则买狗 每次一只 买完为止

方案二 实现Runnable接口

特点:

​ 实现接口 更加有利于代码扩展

​ 实现了任务与线程对象的分离 Runnable接口实现类只负责设计线程任务

​ 可以使用线程池提供线程对象

public class Tickets implements Runnable{
    int n = 100;//因为一般只创建一个实现类对象 因此全局变量是所有线程对象共享的
    //如果真的给每个线程对象 都单独创建了该实现类对象 那么n为各个对象私有的属性
    
    public void run(){
        //每个线程对象都会有自己的run()
        int count = 10;//所有线程对象不共享的数据 作为局部变量 放在run()内部
        。。。
    }   
}
//测试类 推荐只创建一个线程任务对象 可以创建多个线程对象 去绑定这个任务
	Tickets t = new Tickets();//创建唯一的线程任务对象  不建议创建多个
	
	Thread t1 = new Thread(t,"张三"); //创建线程对象 绑定任务 同时为线程命名
	t1.start();
	new Thread(t,"李四").start();

练习:

​ 进入窗口一买猫 进入窗口二 买狗 任意一个宠物 买够10只 则关闭所有窗口

杀死线程

​ t1.stop();
​ t1.destroy();
​ t1.resume();

​ 以上方法已被弃用 推荐通过判断为假结束线程任务

public class Buy implements Runnable {

	boolean bool = true;	//所有线程对象 共享的数据
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		int count = 0;		//每个线程对象私有的属性
		String name = Thread.currentThread().getName();
		
		while(bool) {
			count++;
			if(name.equals("窗口一")) {
				System.out.println(name+"买到第"+count+"只猫");
			}else {
				System.out.println(name+"买到第"+count+"只狗");
			}
			if(count==10) {
				bool = false;
			}
		}
	}
}
//注意 因为未做线程保护 可能会多执行一次
方案三 实现Callable接口

特点:该接口线程任务的方法 带返回值 只能通过线程池提供线程对象

案例:线程一 返回 1累加到10的和 线程二返回 1累乘到10的积

public class YunSuan implements Callable<Integer> {//泛型定义的是方法返回值类型
	@Override
	public Integer call() throws Exception {
		// TODO Auto-generated method stub
		int num = 1;
		
		String name = Thread.currentThread().getName();
		System.out.println(name);
		if(name.equals("pool-1-thread-1")) {
			for(int i =2;i<=10;i++) {
				num+=i;
			}
		}else {
			for(int i =2;i<=10;i++) {
				num*=i;
			}
		}
		return num;
	}

}
//测试类中使用线程池 创建线程对象
线程池

存放线程对象的容器 不用再反复创建线程对象 需要时 直接获取 用完后 归还线程池

线程使用完毕后 会归还到线程池 供后续任务获取使用

线程池一:不固定线程池中线程数量 每次需要就创建 无限创建

​ 默认线程名称 pool-1-thread-1 pllo-1-thread-2… 如果第一个任务已经归还了线程 那么线程池会帮助销毁线程对象 当第二次再申请时 继续创建并获取pool-1-thread-1

		YunSuan ys = new YunSuan();//创建唯一任务对象
		
		//线程池
		//不固定线程数量
		ExecutorService es = Executors.newCachedThreadPool();
		
		Future<Integer> result1 = es.submit(ys);//绑定任务并开始执行 返回带结果的Future对象
		//如果绑定执行的是Runnable实现类对象 则不需要返回值
		System.out.println("线程一:"+result1.get());//通过get()获取值

线程池二:固定线程池中线程数量 达到最大数量后 其他任务等待 等待有归还线程 再获取该线程对象 绑定任务

		//固定线程数量的线程池
		ExecutorService es = Executors.newFixedThreadPool(2);
		
		Future<Integer> result1 = es.submit(ys);//绑定任务并开始执行 返回带结果的Future对象
		System.out.println("线程一:"+result1.get());//通过get()获取值

		Future<Integer> result2 = es.submit(ys);	//任务2 还有线程可以获取
		System.out.println("线程二:"+result2.get());
		
		Future<Integer> result3 = es.submit(ys);	//任务3	只能等待前面的任务归还线程
		System.out.println("线程三:"+result3.get());
总结:

1.接口更适合于资源的共享 (一般只创建一个接口实现类对象)

2.接口避免受到单继承约束 有利于项目的扩展 不占用继承位置

3.实现接口 可以实现线程任务与线程对象的分离 可以单独编写任务 可以利用线程池重复使用线程对象

4.线程池只能用于接口(Runnable Callable) 不能用于继承自Thread的线程对象

练习:

​ 60个人通过5个窗口买50张票 显示第几个人从第几个窗口买到第几张票(暂时不用考虑数据安全)

​ 显示第几个人没买到票

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值