多线程

Java学习第十周

1.线程和进程
线程是依赖于进程存在的。
进程概述
什么是进程呢?通过任务管理器我们就可以看到进程的存在。
概念:进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。

多进程的意义
单进程计算机只能做一件事情。而我们现在的计算机都可以一边玩游戏(游戏进程),一边听音乐(音乐进程),
所以我们常见的操作系统都是多进程操作系统。比如:Windows,Mac和Linux等,能在同一个时间段内执行多个任务。
对于单核计算机来讲,游戏进程和音乐进程是同时运行的吗?不是。
因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和音乐进程间做着频繁切换,且切换速度很快,
所以,我们感觉游戏和音乐在同时进行,其实并不是同时执行的。多进程的作用不是提高执行速度,而是提高CPU的使用率。

多线程有什么意义呢?
多线程的作用不是提高执行速度,而是为了提高应用程序的使用率。
那么怎么理解这个问题呢?
我们程序在运行的使用,都是在抢CPU的时间片(执行权),如果是多线程的程序,那么在抢到
CPU的执行权的概率应该比较单线程程序抢到的概率要大.那么也就是说,CPU在多线程程序
中执行的时间要比单线程多,所以就提高了程序的使用率.但是即使是多线程程序,那么他们
中的哪个线程能抢占到CPU的资源呢,这个是不确定的,所以多线程具有随机性.

JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

2.多线程程序实现的方式1(继承Thread类)
Thread类的基本获取和设置方法
继承Thread类需要重写run()方法
利用start()来启动该方法
public final String getName()//获取线程名称
public final void setName(String name)//设置线程名称
public static Thread currentThread()//获取当前执行的线程

3.线程有两种调度模型:
分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。
Java使用的是抢占式调度模型。
设置和获取线程优先级
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority)//设置线程的优先级(线程的优先级的范围是: 1 - 10)

4.多线程其他方法
public static void sleep(long millis) 线程休眠
public final void join() 等待该线程执行完毕了以后,其他线程才能再次执行(注意:需要在线程启动之后,在调用方法)
public static void yield(): (礼让线程)暂停当前正在执行的线程对象,并执行其他线程。(礼让效果不是很明显)
守护线程: public final void setDaemon(boolean on):
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。 (效果也不是很明显)
public final void stop(): 停止线程的运行(已经过时)
public void interrupt(): 中断线程(这个翻译不太好),查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞

5.多线程(多线程程序实现的方式2)
实现Runnable接口 这种方式扩展性强 实现一个接口 还可以再去继承其他类(可以避免由于Java单继承带来的局限性。)

6.多线程(多线程程序实现的方式3)
实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常
执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类
C:实现步骤
1.创建一个类实现Callable 接口
2.创建一个FutureTask类将Callable接口的子类对象作为参数传进去
3.创建Thread类,将FutureTask对象作为参数传进去
4.开启线程

7.多线程(买电影票出现了同票和负数票的原因分析)

A:加入延迟
	我们前面讲解过电影院售票程序,从表面上看不出什么问题,但是在真实生活中,
	售票时网络是不能实时传输的,总是存在延迟的情况,所以,在出售一张票以后,需要一点时间的延迟
	改实现接口方式的卖票程序,每次卖票延迟100毫秒
B:出现问题了问题
public class SellTickets extends Thread {

	private static int tickets = 100 ;
	private static final Object obj = new Object() ;//设置成静态的 让所有线程对象共享
	
	@Override
	public void run() {
		
		// 卖票
		while(true){
			
			// 同步代码块
			synchronized(obj){//这个对象相当于一把锁 哪个线程先进来先锁住 其他线程进不来 等我进来的这个线程执行完了 释放了这个锁 其他线程才能进来
				
				if( tickets > 0 ){
					
					// 模拟网络延迟
					try {
						Thread.sleep(100) ;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					System.out.println(getName() + "正在出售" + (tickets--) + "张票");
				}
			}
			
		}
	}
	
}
-------------------------------------
public class SellTicketsTest {

	public static void main(String[] args) {
		
		// 创建对象
		SellTickets t1 = new SellTickets() ;
		SellTickets t2 = new SellTickets() ;
		SellTickets t3 = new SellTickets() ;
		
		// 给线程设置名称
		t1.setName("窗口1") ;
		t2.setName("窗口2") ;
		t3.setName("窗口3") ;

		// 启动线程
		t1.start() ;
		t2.start() ;
		t3.start() 	
	}    	
}	

8.多线程(线程安全问题的产生原因分析)
判断一个多线程应用程序是否有问题的标准:
a: 是否是多线程环境
b: 是否存在共享数据
c: 是否存在多条语句同时操作共享数据
使用同步代码块:

格式: 	
	synchronized(对象){//不能在括号了直接new 对象 new 了 就没效果
		要被同步的代码 ;
	}
	这个同步代码块保证数据的安全性的一个主要因素就是这个对象
	注意这个对象 要定义为静态成员变量 才能被所有线程共享
	需要这个对象被所有的线程对象所共享
	这个对象其实就是一把锁.
	这个对象习惯叫做监视器

9.Lock锁的概述和使用
Lock和ReentrantLock
void lock() 上锁
void unlock() 解锁

  public class MyThread implements Runnable {
	
	// 定义票数
	private static int tickets = 100 ;
	
	// 创建Lock锁对象
	private static final Lock lock = new ReentrantLock() ;

	@Override
	public void run() {
		
		while(true){
			
			// 添加锁
			lock.lock() ;
			
			if(tickets > 0){
				
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				System.out.println(Thread.currentThread().getName() + "正在出售" + (tickets--) + "张票");
				
			}
			// 释放锁
			lock.unlock() ;
		}
	}
}

10.多线程(死锁问题概述和使用)
死锁问题概述
如果出现了同步嵌套,就容易产生死锁问题
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
同步代码块的嵌套案例
死锁: 两个或者两个以上的线程,在抢占CPU的执行权的时候,都处于等待状态
举例: 中国人和美国人一起吃饭
中国人使用的筷子
美国人使用的刀和叉
中国人获取到了美国人的刀
美国人获取到了中国人的一根筷子

11.多线程(线程的状态、匿名内部类的方式、定时器)
新建 , 就绪 , 运行 , 冻结 , 死亡
新建:线程被创建出来
就绪:具有CPU的执行资格,但是不具有CPU的执行权
运行:具有CPU的执行资格,也具有CPU的执行权
阻塞:不具有CPU的执行资格,也不具有CPU的执行权
死亡:不具有CPU的执行资格,也不具有CPU的执行权
匿名内部类的方式实现多线程程序
new Thread(){代码…}.start();
new Thread(new Runnable(){代码…}).start();
Timer
public void schedule(TimerTask task, long delay) 在指定的时候到达后, 指定给定的任务
public void schedule(TimerTask task,long delay,long period) 在指定的时候到达后,执行给定的任务, 再等待period时间后,再循环执行给定的任务
TimerTask
public abstract void run()
public boolean cancel()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值