1、线程同步机制是为了解决多线程安全问题进入的机制。
同步代码块
synchronized(对象) //这个对象可以是任意的对象
{
需要被同步的代码
}
同步代码块解决多线程安全问题的原理:对象可以看做是一个锁,线程1进入执行被同步的代码的时候带有锁,另一个线程2想要执行的时候会去判断锁,线程1持有锁,因此线程2无法执行被同步的代码,当线程1结束,就释放锁,其他线程才可以执行被同步的代码--------->这是我自己的理解。。。
综上,同步的是指就是在目前的情况下保证了一次只能有一个线程在执行,其他线程无法执行,这就是同步的锁机制。
弊端:降低效率(因为每次都要判断锁)
2、有可能出现一种情况:多线程安全问题出现后,加入了同步机制,依旧有安全问题,这时,可能是没有遵守同步的前提
同步的前提:多个线程在同步中,必须使用同一个锁,这才是多个线程同步。
例如:synchronized(new Object):每次线程来判断的时候都会new一个对象,每个线程持有的锁都不一样,就会导致加了同步之后依旧有安全问题
多线程是并发访问,那么加了同步之后是否违背了并发访问:不是,因为被同步的代码需要被执行代码的一部分,并不是全部。
3、当函数中的所有代码都需要同步之后,这个时候引入同步函数的概念
将同步synchronized当做一个修饰符
public synchronized void add(int n){
~~~~~~~~~
}
因此同步的表现形式有两种:1、同步代码块 2、同步函数
那么同步函数使用的锁是什么呢?--->是当前调用该函数的对象,this
如果同步函数被静态修饰后,
public static synchronized void add(int n){
~~~~~~~~~
}
由于静态函数不需要对象,所以不持有this关键字,所有它的锁不是this。字节码文件(.class)会在堆中产生一个字节码文件对象,且是唯一的。字节码文件对象的表示方式 类名.class4、同步函数与同步代码块的区别
同步代码块可以使用任意的对象作为锁,同步函数只能使用this作为锁
当一个类中如果需要多个锁,还有多个类中使用一个锁,这时就需要同步代码块来完成。因此建议更多的使用同步代码块。
5、死锁
是多线程加了同步之后的一个弊端。
死锁原因之一:由于锁之间的嵌套,容易引起死锁,因此开发的时候,尽量避免同步嵌套
public static synchronized void add(int n){
synchronized(对象){
~~~~~~~~
}
}
面试题曾经出过如何写出一个死锁程序。可以写一个同步嵌套的程序。
public class myLock {
public static final Object LOCK1 = new Object();
public static final Object LOCK2 = new Object();
}
public class lockDemo implements Runnable{
private boolean flag;
lockDemo(boolean flag){
this.flag=flag;
}
public void run(){
if(flag){
synchronized(myLock.LOCK1){
System.out.println("if---LOCK1");
synchronized(myLock.LOCK2){
System.out.println("if---LOCK2");
}
}
}
else{
synchronized(myLock.LOCK2){
System.out.println("else---LOCK2");
synchronized(myLock.LOCK1){
System.out.println("else---LOCK2");
}
}
}
}
}
public class deadLock {
public static void main(String[] args) {
lockDemo locka=new lockDemo(true);
lockDemo lockb=new lockDemo(false);
new Thread(locka).start();
new Thread(lockb).start();
System.out.println("over");
}
}
·