线程同步
- 概念:由于同一进程的多个线程共享一块储存区域 在他们同时操作一个对象时 需要线程同步
- 线程同步是一种等待机制 多个需要操作一个对象的线程进入对象的等待池 等待前面的线程使用完毕 下一个线程在使用 eg:排队买单
被操作的对象必须定义成静态成员变量 才能被所有线程共享
线程同步的优点:解决了多线程的安全问题
线程同步的缺点:当有多个线程时 每个线程都回去判断同步上的锁 降低了程序的运行效率
同步锁
- 在线程访问对象时 加入锁机制 synchronized————当一个线程获得锁 它独占资源 其他线程必须等待 当它解锁后 其他线程才能执行
public synchronized void method(int args){} ——同步方法
- 若将一个代码较多的方法声明为同步方法————锁的太多 浪费资源 影响效率
synchronized(对象){ 需要同步的代码; } ———同步块 同步监视器
线程进入同步方法或者同步块时 会自动获取锁 在执行完代码退出时会自动释放该锁
只有一个线程会获得该锁——————互斥锁
public class SellTicket implements Runnable{
private static int ticket = 100;
@Override
public void run() {
while(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//sell();
synchronized ("") {
if (ticket <= 0) {
return;
}
System.out.println(Thread.currentThread().getName() + "卖了一张票 还剩" + (--ticket) + "张");
}
}
}
// public synchronized void sell() { // 买票的同步方法
// if(ticket<=0){
// return ;
// }
// System.out.println(Thread.currentThread().getName()+"卖了一张票 还剩"+ (--ticket) +"张");
// }
public static void main(String[] args) {
SellTicket sellTicket = new SellTicket();
Thread thread = new Thread(sellTicket,"售票员1");
Thread thread1 = new Thread(sellTicket, "售票员2");
Thread thread2 = new Thread(sellTicket, "售票员3");
thread.start();
thread1.start();
thread2.start();
}
}
Lock锁 充当 同步锁
- 锁提供了对共享资源的独占访问 每次只能有一个线程对Lock对象加锁
- 线程开始访问共享资源之前应先获得Lock锁
synchronized与Lock的区别
Lock:
- 显式锁——需要手动开启和关闭
- 只有代码块锁
- 性能更好 具有更好的扩展性
Synchronized:
- 隐式锁——出了作用域自动释放
- 有代码块锁和方法锁
推荐:Lock > 同步代码块 > 同步方法
线程死锁
- 当多个线程在执行过程中,需要等待其他线程释放资源才能运行 导致多个线程互相等待对象释放资源的情况————死锁
- 死锁发生的条件
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因为请求资源而等待时 对方获得的资源不释放
- 不剥夺条件:进程已获得的资源 在没有执行完之前 其他进程不能剥夺
- 循环等待条件:多个进程形成一种头尾相接的循环等待资源的关系
只要破坏其中一个死锁条件 就能避免死锁的发生
public class ThreadLock {
public static void main(String[] args) {
DeadLockA deadLockA = new DeadLockA();
Thread thread1 = new Thread(deadLockA, "线程1");
DeadLockB deadLockB = new DeadLockB();
Thread thread2 = new Thread(deadLockB, "线程2");
thread1.start();
thread2.start();
}
}
class DeadLockA implements Runnable {
@Override
public void run() {
synchronized ("A") {
System.out.println("线程1获得了A锁");
}
synchronized ("B") {
System.out.println("线程1获得了A锁和B锁");
}
}
}
class DeadLockB implements Runnable{
@Override
public void run() {
synchronized("B"){
System.out.println("线程2获得了B锁");
}
synchronized ("A"){
System.out.println("线程2获得了B锁和A锁");
}
}
}