Java学习第二十三天知识点(线程安全)
线程同步[线程安全]:
1.产生的原因: 多个线程共享一个资源
2.解决的办法: 使用同步锁(synchronized)
(1)同步方法锁:
a.只能同时被一个线程所持有,当线程执行完这个方法的时候,才会将锁释放
b.锁范围越大,效率越低
c.锁在方法上,实际上锁的还是this对象上加锁
d.锁普通方法: this对象上加锁
锁静态方法: 锁 类.class(类的字节码文件)对象
(2)同步代码块:
a.可以将一部分代码加锁, 同步代码锁,需要借助一个对象
b.加锁的对象: 可以是任意对象,只需要确保是多个线程所共享(对象是唯一的)
c.一般来说都会使用this表示对象
d.同步锁(对象锁),一个对象只能加一把锁,并且只能同时被一个线程所持有的
public void sale(){
//同步代码块
synchronized(this){
System.out.println(Thread.currentThread().getName() + "正在售卖:" + sum--);
if (sum == 0) {
throw new RuntimeException("票已售空!");
//System.out.println("票已售空!");
}
}
System.out.println(1);
}
3.Lock锁 - 接口
1).实现类 -> ReentreantLock(可重入锁)
2).API:
加锁: 锁对象.lock()
解锁: 锁对象.unlock()
3)乐观锁/悲观锁 -> 理解原理(使用场景)
ReentrantLock lock=new ReentrantLock();
public void sale() {
lock.lock();
//同步代码块
System.out.println(Thread.currentThread().getName() + "正在售卖:" + sum--);
if (sum == 0) {
throw new RuntimeException("票已售空!");
//System.out.println("票已售空!");
}
lock.unlock();
System.out.println(1);
}
线程状态:
新建状态: new 一个对象
就绪状态:
a.通过调用start()进入就绪状态
b.run()就绪: 时间片到期,归还/调用yeild()
运行状态
a.cpu分配时间片进入到运行状态
阻塞状态(Blocked):
a.join() -> 造成别的线程阻塞
b.IO阻塞 -> 控制台输入/输出
c.计时等待 -> sleep(100)/wait(100)
d.无线等待 -> wait()/notifyAll()/notify()
e.锁阻塞 -> 加上同步锁/Lock锁
被终止状态: run()结束
join()测试代码:
public class LoadPicture {
public static void main(String[] args) {
Thread read = new Thread(){
@Override
public void run() {
System.out.println("开始加载");
for (int i = 0; i < 100; i++) {
System.out.println("进度"+(i+1));
}
}
};
Thread show = new Thread(){
@Override
public void run() {
System.out.println("等待");
try {
read.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("显示");
}
};
read.start();
show.start();
}
}
线程通信:
1.两个线程有共享资源,并且线程之间有动作交互
2.实现: 使用wait() 和 notify()/notifyAll()
notify() -> 唤醒线程,每次中能唤醒一个线程,只能唤醒在等待的线程
notifyAll() -> 唤醒所有正在等待的线程
注意:wait() 和 notify 需要放在同一个锁中
线程安全测试代码:
loadImage :
public class loadImage extends Thread{
public Picture pic;
public loadImage(Picture pic) {
this.pic=pic;
}
@Override
public void run() {
//加载图片
for (int i = 0; i < 100; i++) {
System.out.println("正在加载图片:"+(i+1)+"%");
}
System.out.println("图片加载完成!");
pic.loadFlag=true;
synchronized (pic){
pic.notify();
}
//加载完后显示图片
//显示完成后下载图片
if (!pic.showFlag){
synchronized (pic){
try {
pic.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("图片下载开始");
for (int i = 0; i < 100; i++) {
System.out.println("正在下载图片:"+(i+1)+"%");
}
System.out.println("图片下载完成");
}
}
showImage :
public class showImage extends Thread{
public Picture pic;
public showImage(Picture pic) {
this.pic=pic;
}
@Override
public void run() {
System.out.println("等待图片加载完成...");
//如果图片没加载完成那么等待
if (!pic.loadFlag) {
synchronized (pic) {
try {
pic.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//如果图片加载完成后执行下面的程序
System.out.println("开始显示图片...");
System.out.println("图片显示完成");
pic.showFlag=true;
synchronized (pic){
pic.notify();
}
}
}
class类:
public class Picture {
public boolean loadFlag;
public boolean showFlag;
}
主函数:
public class Main {
public static void main(String[] args) {
Picture pic = new Picture();
loadImage li = new loadImage(pic);
showImage si = new showImage(pic);
li.start();
si.start();
}
}