Java基础04 线程同步 与 死锁 154155 156

本文深入探讨了多线程环境中共享数据的安全问题,详细介绍了三种实现线程同步的方法:同步代码块、同步方法和使用Lock(ReentrantLock),并讨论了同步准则以避免死锁和性能风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

7、线程同步

1、多线程共享数据必须使用同步
在多线程的操作中,多个线程有可能同时处理同一个资源,这就是多线程中的共享数据。

这样是不安全的 两个4 两个0
在这里插入图片描述
2、线程同步
解决数据共享问题,必须使用同步,所谓同步就是指 多个线程在同一个时间段内只能有一个线程执行指定代码,其他线程要等待此线程完成之后才可以继续执行。

线程进行同步,有以下三种方法:
(1)同步代码块
synchronized(要同步的对象){
要同步的操作 ;
}

把要同步的那段代码 用synchronized的大括号括起来
小括号要填一个对象进去
这样 就在线程里建一个通用对象obj (这个对象写什么都行 保证多个线程使用的是同一个对象就可以 integer啥的都可以 就单纯表示一个锁的意思
在这里插入图片描述
或者为了图省事 直接写this 当前对象 这样更方便


这样main调用时 t1 t2 使用的就是同一个对象
在这里插入图片描述
这样就安全了
在这里插入图片描述


(2)同步方法
public synchronized void method(){
要同步的操作 ;
}

或者把需要同步的操作代码 抽象出来 放进 同步 方法里面
在for循环调用method方法

同步方法:同步的对象是当前对象(this)
在这里插入图片描述


(3)Lock(ReentrantLock)
就不用synchronized关键字了
使用锁
更加灵活 想什么时候锁 什么时候解锁 都可以操作 或者加判断条件什么的 synchronized做不到这一点

使用ReentrantLock 互斥锁这个类

在这里插入图片描述
lock.lock();//锁
lock.unlock();//释放锁
这两句夹的就决定了锁的内容
在这里插入图片描述
为了保证一定解锁 可以使用try finally 防止不解锁 避免死锁


3、同步准则
当编写 synchronized 块时,有几个简单的准则可以遵循,这些准则在避免死锁和性能危险的风险方面大有帮助:

(1)使代码块保持简短。把不随线程变化的预处理和后处理移出synchronized 块。(即不需要同步的不要放在synchronize所管 辖的区域 尽量保持简短 多线程共享数据,会有安全问题 ,使用同步可以解决安全问题 ,但同时会牺牲性能,所以同步的代码块要尽量保持简短,把不随数据变化的相关代码移除同步块 )
(2)不要阻塞。如InputStream.read()。
(3)在持有锁的时候,不要对其它对象调用(同步)方法。(在synchronized或者锁的内容里面 不要调用其他对象方法 万一那个对象方法也是同步的 要小心 你等他 他等你 会造成死锁 不会报错 程序死在那了)


  • Created by vince on 2017/6/5.
  • 1多线程共享数据时,会发生线程不安全的情况
  • 2多线程共享数据必须使用同步
  • 3实现同步的三种方法:
  • (1)使用同步代码块
  • (2)使用同步方法
  • (3)使用Lock(更灵活的代码控制)
  • 多线程共享数据,会有安全问题 ,使用同步可以解决安全问题 ,但同时会牺牲性能,所以同步的代码块要
  • 尽量保持简短,把不随数据变化的相关代码移除同步块,不要阻塞

package com.vince;

import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by vince on 2017/6/5.
 * 1多线程共享数据时,会发生线程不安全的情况
 * 2多线程共享数据必须使用同步
 * 3实现同步的三种方法:
 * (1)使用同步代码块
 * (2)使用同步方法
 * (3)使用Lock(更灵活的代码控制)
 * 多线程共享数据,会有安全问题 ,使用同步可以解决安全问题 ,但同时会牺牲性能,所以同步的代码块要
 * 尽量保持简短,把不随数据变化的相关代码移除同步块,不要阻塞
 */
public class ThreadDemo4 {

    public static void main(String[] args) {
        MyRunnable5 mr5 = new MyRunnable5();

        Thread t1 = new Thread(mr5);
        Thread t2 = new Thread(mr5);
        t1.start();
        t2.start();
    }
}

class MyRunnable5 implements Runnable {

    private int ticket = 10;//售票

    //private Object obj = new Object();//同步锁
    @Override
    public void run() {
        for (int i = 0; i < 300; i++) {
//            if (ticket > 0) {
//                synchronized (this) {
//                    ticket--;
//                    try {
//                        Thread.sleep(1000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    System.out.println("您购买的票剩余" + ticket + "张");
//                }
//            }
            method();
        }
    }

    //同步方法:同步的对象是当前对象(this)
    private synchronized void method() {
        if (ticket > 0) {
            ticket--;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("您购买的票剩余" + ticket + "张");
        }
    }
    //互斥锁
    ReentrantLock lock = new ReentrantLock();
    //Lock实现同步
    private void method2() {
        lock.lock();//锁
        try {
            if (ticket > 0) {
                ticket--;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("您购买的票剩余" + ticket + "张");
            }
        }finally {
            lock.unlock();//释放锁
        }
    }
}

死锁

过多的同步有可能出现死锁,死锁的操作一般是在程序运行的时候才有可能出现。

多线程中要进行资源的共享,就需要同步,但同步过多,就可能造成死锁。

下面举一个死锁的例子 只是个例子 写的时候不要这么写

package com.vince;

/**
 * Created by vince on 2017/6/5.
 * 线程死锁:在一个同步方法中调用了另一个对象的同步方法,可能产生死锁
 *
 */
public class DeadThreadDemo {

	public static void main(String[] args) {
		new DeadThread();
	}

}

//顾客
class Customer{
	public synchronized void say(Waiter w){
		System.out.println("顾客说:先吃饭再买单!");
		w.doService();
	}

	public synchronized void doService(){
		System.out.println("同意了,买完单再吃饭!");
	}
}
//服务员
class Waiter{
	public synchronized void say(Customer c){
		System.out.println("服务员说:先买单再吃饭!");
		c.doService();
	}
	public synchronized void doService(){
		System.out.println("同意了,吃完饭再买单!");
	}
}


//死锁线程
class DeadThread implements Runnable{
	Customer c = new Customer();
	Waiter w = new Waiter();
	public DeadThread(){
		new Thread(this).start();
		w.say(c);
	}
	@Override
	public void run() {
		c.say(w);
	}
}


使用idea不会 功能太强大了 死锁给避免了 笑哭
在这里插入图片描述
结果死锁了

线程死锁:在一个同步方法中调用了另一个对象的同步方法,可能产生死锁
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值