锁 与线程

本文详细介绍了Java中的线程安全问题,强调了`synchronized`关键字在确保线程安全中的作用,包括修饰代码块、方法和静态方法。同时,讲解了守护线程的概念,即主线程结束时,守护线程也随之结束。接着,探讨了死锁的现象及其避免方法,并举例说明。此外,还展示了生产者消费者模式的应用,演示了如何通过`wait()`和`notify()`方法实现线程间的通信。
摘要由CSDN通过智能技术生成

线程是不安全的,随机抢占的, 线程抢到资源以后,加上锁以后,这个线程先执行结束,会自动的释放锁

用法:
1.修饰一个代码块
2.修饰一个方法
3.修饰一个静态方法
4.修饰一个类

1.修饰代码块

语法格式

​ 一个线程访问一个对象中synchronised(this)同步代码块的时候,其他视图访问该对象的线程就会被阻塞

synchronised (this) {
		代码块
}

class SynThread1 implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		//开始锁for循环 加上锁
		/**
		 * 在同一时刻   线程会进到run方法中,发现有一个锁
		 * 假如SYN抢到了这个锁  syn 线程在锁的外面等待着
		 * SYN抢到了,就要把for循环代码执行完,锁会自动释放
		 * syn 才抢到,加锁了,也要把下面for循环执行完
		 */
		synchronized (Object.class) {
			//加锁的这一部分,只会让一个线程先执行完。释放锁另外一个线程再进来
			//this 不是线程1  也不是线程2
			System.out.println(this.toString());
			for (int i = 0; i < 5; i++) {
				System.out.println("线程的名字:" +Thread.currentThread().getName() );
			}
		}
	}	
}
public class Demo2 {
	public static void main(String[] args) {
		//开启的时候使用的是两个不同的线程类对象
		Thread thread = new Thread(new SynThread1(), "SYN");
		thread.start();
		Thread thread1 = new Thread(new SynThread1(), "syn");
		thread1.start();
		//以上写法依旧是线程不安全的  乱的,为啥?			
	}
}

2.守护线程

主线程挂掉,守护线程随即也要挂掉,守护线程要依附于主线程执行

class MyThread6 implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("软件更新中..........");
		for (int i = 1; i < 101; i++) {
			System.out.println("downloding:" + i + "%");
		}
	}
}
public class Demo4 {
	public static void main(String[] args) {
		Thread thread = new Thread(new MyThread6());
		thread.setDaemon(true);//将线程设置为守护线程
		thread.start();
		//当主线程执行结束以后,守护线程即使霉运执行完也要挂掉
		//更新软件  ,软件呢运行。退出软件,更新就失败了
		for (int i = 1; i < 31; i++) {
			System.out.println("主程序在运行");
		}
	}
}

3.死锁

应用场景:并发的时候,多线程的,互不相让。

死锁一定发生在多线程之间,使用锁的目的就是线程安全的,但是物极必反。

死锁是一个状态,当两个线程互相持有对方的需要的资源的时候,却不主动释放自己的资源的时候,大致大家都用不了,线程就无法往下执行了。

知道有这个概念,然后去避免它

  • 线程的几个重要的方法

wait() notify() notifyALl() 方法 都是Object 类下面的方法

  • wait();

​ 1.让线程进入到等待状态。

​ 2.wait方法和锁一起使用。

​ 3.需要通过对象调用。锁对象来调用

  • notify():

​ 1.唤醒线程

​ 2.方法和锁一起使用。

​ 3.需要通过对象调用。锁对象来调用

在一个线程中书写wait方法,此线程就会阻塞,线程处于等待状态。这个时候需要另外一个线程调用notify方法进行唤醒,让等待的线程继续执行

9.生产者消费者模式

线程之间进行通信的一种方案

package com.qfedu.c_shengchanzhe;


//共享资源,  两个线程都要操作同一个商品
class Goods {
	private String name;//商品的名字
	private double  price;//商品的价格
	private boolean shouldProduct;//没有商品是true。   有商品的话就是false
	public Goods() {
		
	}
	public Goods(String name, double price, boolean shouldProduct) {
		
		this.name = name;
		this.price = price;
		this.shouldProduct = shouldProduct;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
   
	public boolean isShouldProduct() {
		return shouldProduct;
	}
	public void setShouldProduct(boolean shouldProduct) {
		this.shouldProduct = shouldProduct;
	}
	//打印对象的时候是一个字符串,如果不写toString方法,打印的会是对象的内存地址
	@Override
	public String toString() {
		return "Goods [name=" + name + ", price=" + price + ", shouldProduct=" + shouldProduct + "]";
	}
	
	
	
}
//写两个线程
//消费者线程
class Customer implements Runnable {
	//由于两个线程需要共享一个资源,商品资源需要实例化,给Customer
	private Goods goods;
	public  Customer(Goods goods) {
		this.goods = goods;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		//消费多个  无限制消费
		while (true) {
			synchronized (goods) {
				//false  goods 这个对象下面的一个属性叫shouldProduct
				if (!goods.isShouldProduct()) {
					//执行的不需要生产的代码
					//开始直接购买
					System.out.println("消费者购买了:" + goods.getName() + ",价格为:" + goods.getPrice());
					//购买完以后,这个商品就没有了,需要生产,重新标记为true
					goods.setShouldProduct(true);
					//购买完以后商品没了,要去唤醒生产者  去干活,开始生产了
					//唤醒生产者
					goods.notify();
				} else {
					//需要生产的代码,消费者进入到等待状态
					System.out.println("3");
					try {
						goods.wait();//没有商品的时候,需要生产的时候,消费者进入到阻状态
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("4");
				}
			}
		}
	}
}
//生产者线程
class Productor implements Runnable {
	private Goods goods;
	public  Productor(Goods goods) {
		this.goods = goods;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		int count = 0;
		while (true) {
			try {
				//让生产者线程睡一会
				Thread.sleep(4000);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			synchronized (goods) {
				
				if (goods.isShouldProduct()) {
					//需要生产  shouldProduct  变量true
					if (count % 2 == 0) {
						goods.setName("奥迪RS8");
						goods.setPrice(54.3);
						
					} else {
						goods.setName("五菱神车");
						goods.setPrice(20.9);
					}
					//生产完以后,立马标记为  false
					goods.setShouldProduct(false);
					System.out.println("生产者生产了:" + goods.getName() + ",价格为:" + goods.getPrice());
					count++;
					//已经生产好了,去唤醒消费者,让消费者去消费
					goods.notify();
				} else {
					//不需生产 的话,就能直接  让生产者等待
					System.out.println("1");
					try {
						goods.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("2");
				}
			}
			
		}
	}
	
}
public class Demo1 {
	public static void main(String[] args) {
		//false 不需要生产,证明有产品
		Goods goods = new Goods("保时捷" , 67.8, false);//true 需要被生产
		Customer customer = new Customer(goods);
		Productor productor =  new Productor(goods);
		//想让哪个线程抢到合适?
		//消费者先抢到线程
		new Thread(customer).start();
		new Thread(productor).start();
		
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值