java线程同步
锁:
首先看下下面的代码:
1.多个线程运行时,是交替运行的。22/23行的代码是为了使线程的交替运行表现得更加明显,也可以不要的。
2.有两种同步的方法,public synchronized void add(String name){...},不要把这个当成了一种同步方法,正确理解为:执行这个方法的过程当中,当前对象被锁定(貌似很多企业面试的时候就考这个)。
3.加锁之前,你会发现程序运行结果是:t1你是第2个使用timer的线程 t2你是第2个使用timer的线程
枷锁之后,t1你是第1个使用timer的线程 t2你是第2个使用timer的线程(实现了同步)
加锁了之后,只有当当前代码块执行完毕之后,第二个线程才会执行。
死锁:
线程1和线程2都锁定了两个对象A和B,但是对象A正在线程1中使用,对象B正在线程2中使用。对于线程1,它的同步代码块要运行成功,必须要获取对象B的资源,但是对象B被锁定了,于是线程1必须等待线程2运行完成;对于线程2,它的同步代码块要运行成功,必须要获取对象A的资源,但是对象A被锁定了,于是线程2必须等待线程1运行完成,这样便出现了死锁。(两个线程都锁定了两个对象资源)。
下面就是一个简单的死锁代码
在这里注明下本人的问题:调用Thread thread = new Thread();线程对象便处于新建状态,此时,它已经有了相应的内存空间和其他资源,Thread thread1 = new Thread()
Thread thread2 = new Thread()
而不是需要调用多个run()方法才会创建多线程
如何避免线程死锁?
1、尽量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
2、尽量使用java.util.concurrent(jdk 1.5以上)包的并发类代替手写控制并发,比较常用的是ConcurrentHashMap、ConcurrentLinkedQueue、AtomicBoolean等等,实际应用中java.util.concurrent.atomic十分有用,简单方便且效率比使用Lock更高 。
3、不要锁住两个对象,尽量锁住一个对象,也叫把锁的粒度加粗,比如上面的程序,锁定TestDeadLock而不是锁定它下面的两个小对象。
4、尽量减少同步的代码块。
下面推荐一个经典视频,也是一道面试经典题目:https://ke.qq.com/webcourse/index.html#course_id=216052&term_id=100255386&taid=1276786403134452&vid=a1401a6marp
如何查看死锁?
即:用命令行工具编译运行java程序之后,如果产生了死锁就按Ctrl+(Fn+B)键,就会弹出死锁的信息,如下: