Java--线程的同步与死锁
程序员文章站
2022-03-10 16:02:56
...
目录索引
线程的同步
当多个线程访问同一资源时,可能会造成资源的不同步,比如:可能由于网络延迟,导致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());
}
}
}
上面代码的理想状态应该是有两组数据(“小猫-吃鱼”和“小狗-吃骨头”)交替执行,而真实的结果是,两组数据混乱(“小猫-吃骨头”和“小狗-吃鱼”),且会重复出现,所以可以使用同步和等待与唤醒处理
等待与唤醒:
- 等待机制:
- 死等: public final void wait() throws InterruptedException;
- 设置等待时间: public final void wait(long timeout) throws InterruptedException;
- 设置等待时间: public final void wait(long timeout, int nanos) throws InterruptedException;
- 唤醒机制
- 唤醒第一个等待线程: public final void notify();
- 唤醒全部等待线程: 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());
}
}
}
上一篇: 接口和抽象类的区别
下一篇: 抽象类、接口和普通类的区别