一 线程同步
java中提供了线程同步机制,它能够解决上述的线程安全问题。
线程同步的方式有两种:
方式1:同步代码块
方式2:同步方法
1 同步代码块
同步代码块: 在代码块声明上 加上synchronized
synchronized (锁对象) { 可能会产生线程安全问题的代码 }
同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。
使用同步代码块,对电影院卖票案例中Ticket类进行如下代码修改
package com.oracle.demo01; public class Myticket implements Runnable { private int ticket=100; private Object obj=new Object(); public void run() { while(true){ synchronized (obj) { if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"出售第"+ticket--+"张票"); } } } } }
运行结果为:
这样就解决了线程安全的问题
2 同步方法
同步方法:在方法声明上加上synchronized
public synchronized void method(){ 可能会产生线程安全问题的代码 }
同步方法中的锁对象是 this
使用同步方法,对电影院卖票案例中Ticket类进行如下代码修改:
package com.oracle.demo01; public class Myticket2 implements Runnable { private int ticket=100; //同步方法是否有锁对象?有 this //静态同步方法有锁对象?有,MyTicket2.class //同步怎么保证安全性?没有锁的线程不能执行只能等 //加了同步,线程进同步判断锁的时候,比如,获取锁,释放锁,导致运行速度慢 //StringBuilder比StringBuffer快的原因 //StringBuffer里面的所有方法都加了同步关键字,所以慢,但安全 //StringBuilder是没有的,所以快,但不安全 public synchronized void sale(){ //可能会产生线程安全问题的代码 if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"出售第"+ticket--+"张票"); } } public void run() { while(true){ sale(); } } }
二 死锁
同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。
package com.oracle.demo02; public class DeadLock implements Runnable { private int i=0; public void run() { while(true){ if(i%2==0){ //先进A同步,再进B同步 synchronized (LockA.locka) { System.out.println("if...locka"); synchronized (LockB.lockb) { System.out.println("if...lockb"); } } }else{ //先进B同步,再进A同步 synchronized (LockB.lockb) { System.out.println("else...lockb"); synchronized (LockA.locka) { System.out.println("else...locka"); } } } i++; } } }
程序无线等待