同步:多个操作在同一个时间段内只能有一个线程执行,其他线程要等待此线程完成后才能运行。
判断线程是否有安全性问题
1、是否是多线程环境
2、是否有共享数据
3、是否有多条语句操作共享数据
同步的目的:解决线程安全性问题
同步分为同步代码块和同步方法
同步代码块的格式
格式: synchronized(同步对象) {
需要同步的代码;
}
对象可以是任意对象,但是对象必须要在同步的代码外面建立 一般将当前对象(this)设置成同步对象
如private Object obj = new Object();
synchronized (obj) {}
同步的特点
前提条件:1、多个线程
2、多个线程使用的是同一个锁对象
好处:解决了线程的安全性问题
弊端:效率低,耗时
同步方法的格式及对象问题
同步方法的格式:把同步关键词加在方法上。 如private synchronized int ticket =100;
对象为this
静态方法的锁对象:类的字节码文件对象,即class文件 如Sell.class
代码
package cn.idcast4;
/* 电影院共有100张票要卖,共有3个窗口,设计程序实现卖票功能
*/
public class SellTicket implements Runnable {
private int ticket = 100;
private Object obj = new Object();
@Override
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--) + "张票");
}
}
}
}
}
package cn.idcast4;
public class SellTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
为了更清晰的表达在哪里加锁和释放锁,JDK5提供了Lock Lock是个接口
Lock的方法
void Lock:加锁
void unLock:释放锁
由于是接口,所以ReentrainLock是实现类
代码可以这样显示: private Lock l = new ReentrainLock();
try{ 用try和finally的原因是由于锁住的代码可能报错
l.lock;
} finally {
l.unlock;
}
死锁:是指两个或者两个以上的线程在执行的过程中,因为争夺资源产生的一种相互等待现象。
产生死锁的条件:
1、互斥条件:一个资源每次只能被一个进程使用。
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁的方法:阻止循环等待条件。