线程的同步
问题
- 多个线程执行的不确定性引起执行结果的不稳定
- 多个线程的共享,会造成操作的不完整性,会破坏数据
同步代码块
- 操作共享数据的代码,即为需要被同步的代码。
- 共享数据:多个线程共同操作的变量
- 同步监视器,俗称:锁,任何类的对象都可以充当锁。多个线程必须要共用同一把锁。
局限性
- 局限性:操作同步代码时,只能有一个线程参与,其它线程等待,相当于是一个单线程的过程,效率比较低。
选择考虑
- 在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器,而在继承Thread类创建多线程的方式中,慎用this,可以考虑使用当前类作为同步监视器。
代码
synchronized(同步监视器){
需要被同步的代码
}
比如卖票代码,可以改成
class window1 implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
ticket--;
}else break;
}
}
}
}
同步方法
如果操作共享数据的代码完整地声明在一个方法中,就可以将这个方法声明为同步的。
此时的同步监视器为this。
public synchronized void 方法(){}
同步方法里的同步监视器
同步方法仍然涉及到同步监视器,只是不需要显式的声明。
非静态的同步方法,同步监视器为this
静态的同步方法,同步监视器为当前类本身。
线程安全的单例模式(懒汉式)
class Bank{
private Bank(){}
private static Bank instance = null;
public static synchronized Bank getInstance(){
//方式一 效率较差
// synchronized (Bank.class){
// if(instance==null){
// instance = new Bank();
// }
// return instance;
// }
//方式二 效率稍高
if(instance==null){
synchronized (Bank.class){
if(instance==null){
instance = new Bank();
}
}
}
return instance;
}
}
死锁
定义
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。
解决方法
专门的算法和原则
尽量减少同步资源的定义
尽量避免嵌套同步