线程-02

简介

继续上一次的线程01,有问题欢迎指正

1.线程的生命周期

1.新建:创建线程对象,没有调用start
2.准备:线程已经调用start方法,还没有分配到CPU时间片
3.运行:线程分配到了CPU,开始执行run方法
4.阻塞:线程遇到一些情况,暂停执行
5.死亡:run方法执行完

什么情况下会遇到阻塞?
1.调用sleep 2.调用wait 3.调用suspend(废弃) 4.进行IO操作

2.线程的同步问题

出现同步的情况:多个线程同时 操作一个资源(对象、方法等) 上面三个条件很重要 全部都是需要满足的

出现原因:操作系统中,多个线程执行时抢占式的,线程在执行时被其他线程抢占CPU,导致方法没有完全执行完,数据可能被其他线程修改,可能出现数据不一致的情况,这就是线程同步问题。

解决方法:上锁机制:将资源上锁,一个线程执行完,下个线程才能访问。

1.同步方法:一个线程执行方法时,整个方法上锁,其他线程不能调用,线程执行完,其他线程才能进入。在定义方法时,添加关键字。例:

public sychronized 返回类型 方法(...){

}

同步方法的锁对象是this。

2.同步代码块
对一段代码上锁,一个线程进入代码块时,代码块上锁,其他线程不能调用,线程执行完,其他线程才能进入。

sychronized(锁对象){
	代码块
}

注意:锁对象可以使任意的成员变量,不能是局部变量,因为局部变量每个线程执行方法时都会创建新的对象,新的对象不能对其他的线程起到作用。

3.同步锁
在java1.5出现,在java.util.concurrent同步包中
Lock接口
实现类:
ReentrantLock -------重入锁
ReentrantReadLock -------读锁
ReentrantWriteLock -------写锁
创建锁:
Lock lock = new ReentrantLock();
注意:该锁对象必须是成员变量
主要方法:
lock() 上锁
unlock() 释放锁(上锁后必须确保能释放锁,否则出现死锁)
代码:

.lock();
try{
	代码块
}finally{.unlock();
}

性能比较:同步锁 > 同步块 > 同步方法

sychronized机制的原理:
一旦将方法或代码块添加sychronized后,jvm启动monitor(监视器)对进入方法或代码的线程进行监控,当前的线程持有锁,其他线程想进入方法或代码块监视器会进行阻止,只有当前线程执行完,会释放锁,其他线程才能进入。

面试题04:StringBuilder和StringBuffer的区别
两个类用法相同,StringBuffer所有方法上锁,适合多线程,另一个没有上锁,适合单线程。

面试题05:同步方法和同步代码块的区别
1.锁的范围不同(锁粒度不同)
同步方法锁粒度大,锁整个方法,同步块粒度小,锁一段代码
2.性能不同
锁粒度越大,性能越低,同步块性能高于同步方法
3.灵活性不同
同步块可以选择锁某段代码,更灵活

3.单例模式

是什么?是一种经典的设计模式,设计模式是解决某些问题的经验的总结(各个领域)。

单例模式能实现一个类只有一个实例

应用场景:
1.某些特殊业务需求。2.节约系统资源

实现方法:
1.将所有的构造方法定义为私有的private
2.在类中定义一个私有的静态的对象,该对象可以使用new创建。
3.在类中定义一个静态方法,用于返回静态对象

单例模式有两种:
1.饿汉式
一开始就创建对象
问题:如果用户不需要创建对象,对象还是会被创建,消耗了内存

2.懒汉式
一开始不创建对象,调用获得对象的静态方法时,再创建对象,但是懒汉式单例模式存在线程同步问题

public class LazySingleton{
	//定义静态对象
	private static LazySingleton mySingleton = null;
	//将构造方法定义为私有
	private LazySingleton(){}
	//定义静态方法返回对象
	public static LazySingleton getInstance(){
		//外层判断,如果对象不为空,就不执行同步块,提高性能。
		if(mySingleton == null){
		//同步块,保证if判断和创建对象在一个线程里完整执行。
			synchronized(LazySingleton.class){
				//多个线程可能同时执行这一行,因此需要同步块。
				if(mySingleton==null){
					mySingleton = new LazySingleton ();
				}
			}
		}
		return mySingleton;
	}
}

面试题06:需要会手写,以及了解为什么需要两层判断

4.线程死锁

出现情况:两个线程都持有对方的锁,又都需要对方持有的锁,形成循环等待。
避免:编程时不要使用同步块的嵌套

面试题07:利用同步块,写出死锁案例

public class DeadLock{
	private Object lock1 = new Object();
	private Object lock2 = new Object();
	public void func1(){
		//当线程运行时,得到lock1这个锁对象
		synchronized(lock1){
			//该线程需要lock2这个锁对象,但是可能被其他线程拿到了。
			synchronized(lock2){}
		}
	}
	public void func2(){
		//当线程运行时,得到lock2这个锁对象
		synchronized(lock2){
		//该线程需要lock1这个锁对象,但是可能被其他线程拿到了。
			synchronized(lock1){}
		}
	}
	main{
		//这样是概率出现死锁。
		DeadLock deadLock = new DeadLock();
		new Thread(()->{
			deadLock.func1();
		}).start();
		new Thread(()->{
			deadLock.func2();
		}).start();
	}
}

5.servlet的线程同步问题

Servlet时单实例多线程的
一个Servlet类只有一个实例(节约服务器资源),每个用户访问servlet实例时,服务器会创建新的线程,每个用户的操作相互独立不影响。

多个线程同时访问一个Servlet实例时就可能出现线程同步问题。
解决方法:
1.上锁机制
问题:大量用户都需要排队访问,效率低。

2.使用局部变量
大量用户访问的数据应该使用局部变量,在Servlet中不要使用成员变量。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值