Java--线程的同步与死锁

线程的同步

当多个线程访问同一资源时,可能会造成资源的不同步,比如:可能由于网络延迟,导致A窗口卖票的时候看到有一张剩余,但其实已经被B窗口给卖出去了,所以此时的资源不同步。由此引出线程的同步处理
在这里插入图片描述
图中锁的功能可以用synchronized关键字来实现,利用此关键字可以定义同步方法同步代码块,使此时操作只允许一个线程执行。
同步会使程序的整体性能降低

class MyThread implements Runnable {
    
    
	private int ticket = 10 ; //总票数为10张
	public synchronized boolean sale( ) {
    
    //定义同步方法
		if (this.ticket > 0) {
    
    
			try {
    
    
				Thread . sleep(100);//模拟网络延迟
			} catch (InterruptedException e) {
    
    
				e. printStackTrace();
			}
		 	System.out.println(Thread.currentThread().getName()+"卖票,ticket="+this.ticket --);
			return true ;
	    } else {
    
    
			System. out . print1n("*****票已经卖光了 ****");
			return false ;
		}
	}
	@override
	public void run() {
    
    
		while (this.sale()) {
    
    
			;
		}
	}
}
public class ThreadDemo {
    
    
	public static void main(String[] args) throws Exception {
    
    
		MyThread mt = new MyThread() ;
		new Thread(mt, "票贩子A").start();
		new Thread(mt, "票贩子B").start();
		new Thread(mt,"票贩子C").start();
	}
}

线程的死锁

线程同步时可能出现的问题,若干个线程彼此互相等待对方让出资源若干个线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁

生产者–消费者模型

  • 生产者负责信息内容的生产;
  • 每当生产者生产完成–项完整的信息之后消费者要从这里面取走信息;
  • 如果生产者没有生产者则消费者要等待它生产完成,如果消费者还没有对信息进行消费,则生产者应该等待消费处理完成后再继续生产。
    在这里插入图片描述
public class ThreadDemo {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Message msg = new Message() ;
		new Thread(new Producer(msg)).start(); //I 启动生产者线程
		new Thread (new Consumer (msg)).start(); // 启动消费者线程
	}
}
class Message {
    
    //产品
	private String title ;
	private String content ;
	public void setContent(String content) {
    
    
		this. content = content ;
	}
	public void setTitle(String tit1e) {
    
    
		this.title = title; .
	}
	public String getContent() {
    
    
		return content ; 
	}
	public String getTit1e() {
    
    
		return title;
	}
}
class Producer implements Runnable {
    
    //生产者
	private Message msg ;
	public Producer(Message msg) {
    
    //获取Message
		this.msg = msg ;
	}
	@Override
	public void run() {
    
    
		for(int x=0;x<100;x++){
    
    
			if (x%2==0) {
    
    //生产第一组数据
				this.msg.setTitle("小猫");
				this.msg.setContent("吃鱼");
			} else {
    
    //生产第二组数据
				this.msg.setTitle("小狗");
				this.msg.setContent("吃骨头");
			}
		}
	}
}
class Consumer implements Runnable {
    
    //消费者
	private Message msg ;
	public Consumer(Message msg) {
    
    
		this.msg = msg ;
	}
	@Override
	public void run() {
    
    
		for (int x=0;x<100;X++) {
    
    
			System. out . println(this . msg. getTitle() + " - " + this .msg. getContent());
		}
	}
}

上面代码的理想状态应该是有两组数据(“小猫-吃鱼”和“小狗-吃骨头”)交替执行,而真实的结果是,两组数据混乱(“小猫-吃骨头”和“小狗-吃鱼”),且会重复出现,所以可以使用同步等待与唤醒处理
等待与唤醒:

  • 等待机制:
  1. 死等: public final void wait() throws InterruptedException;
  2. 设置等待时间: public final void wait(long timeout) throws InterruptedException;
  3. 设置等待时间: public final void wait(long timeout, int nanos) throws InterruptedException;
  • 唤醒机制
  1. 唤醒第一个等待线程: public final void notify();
  2. 唤醒全部等待线程: public final void notifyAll();
public class ThreadDemo {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Message msg = new Message() ;
		new Thread(new Producer(msg)).start(); //I 启动生产者线程
		new Thread (new Consumer (msg)).start(); // 启动消费者线程
	}
}
class Message {
    
    //产品
	private String title ;
	private String content ;
	private boolean flag = true ; //表示生产或消费的形式
		// flag = true:允许生产,但是不允许消费
		// flag = false: 允许消费,不允许生产
	public synchronized void set(String title,String content) {
    
    //同步处理,并使小猫和鱼绑定小狗和骨头绑定
		if (this.flag==false) {
    
     // 无法进行生产,应该等待被消费
			try {
    
    
				super.wait();//等待
			} catch (InterruptedException e) {
    
    
				e. printStackTrace();
			}
		}
		this.title = title ;
		this. content = content ;
		this.flag=false;//已经生产过了
		super.notify();//唤醒等待的线程
	}
	public synchronized String get() {
    
    
		if (this.flag == true) {
    
     // 还未生产,需要等待
			try {
    
    
				super.wait( );
			} catch (InterruptedException e) {
    
    
				e. printStackTrace();
			}
		}
		try{
    
    
			return this. title +" - "+ this.content;
		}finally {
    
    //不管如何都要执行
			this.flag=true;//继续生产
			super.notify();//唤醒等待线程
		}
	}
}
class Producer implements Runnable {
    
    //生产者
	private Message msg ;
	public Producer(Message msg) {
    
    //获取Message
		this.msg = msg ;
	}
	@Override
	public void run() {
    
    
		for(int x=0;x<100;x++){
    
    
			if (x%2==0) {
    
    //生产第一组数据
				this.msg.setTitle("小猫","吃鱼");
			} else {
    
    //生产第二组数据
				this.msg.setTitle("小狗","吃骨头");
			}
		}
	}
}
class Consumer implements Runnable {
    
    //消费者
	private Message msg ;
	public Consumer(Message msg) {
    
    
		this.msg = msg ;
	}
	@Override
	public void run() {
    
    
		for (int x=0;x<100;X++) {
    
    
			System.out.println(this.msg.get());
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43337254/article/details/108103414