多线程
线程同步机制
不安全案例
public class UnsafeBuyTicket {
public static void main ( String [ ] args) {
BuyTicket buyTicket= new BuyTicket ( ) ;
new Thread ( buyTicket, "zs" ) . start ( ) ;
new Thread ( buyTicket, "ls" ) . start ( ) ;
new Thread ( buyTicket, "ww" ) . start ( ) ;
}
}
class BuyTicket implements Runnable {
private int num= 10 ;
private boolean flag= true ;
public void Buy ( ) {
if ( num< 1 ) {
flag= false ;
return ;
}
try {
Thread . sleep ( 1000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System . out. println ( Thread . currentThread ( ) . getName ( ) + "买到了第" + num-- + "张票" ) ;
}
@Override
public void run ( ) {
while ( flag) {
Buy ( ) ;
}
}
}
public class UnsafeList {
public static void main ( String [ ] args) throws InterruptedException {
List < String > list= new ArrayList < > ( ) ;
for ( int i = 0 ; i < 10000 ; i++ ) {
new Thread ( ( ) -> {
list. add ( Thread . currentThread ( ) . getName ( ) ) ;
} ) . start ( ) ;
}
Thread . sleep ( 3000 ) ;
System . out. println ( list. size ( ) ) ;
}
}
并发
线程同步
其实就是一个等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用 统一进程的多个线程共享同一存储空间,为了保证数据在方法中被访问时的正确性,在访问时加入了锁机制synchronized ,当一个线程获得对象的排他锁,独占资源,其他线程必须等待。但会存在如下问题:
一个线程持有锁会导致其他所需要的此锁的线程挂起; 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题; 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题 synchronized 关键字 :synchronized方法控制对象的访问,每个对象对应一把锁,每个synchronize方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面阻塞的线程才能获得这个锁,继续执行缺陷:若将一个大的方法声明为synchronized将会影响效率 方法里面需要修改的内容才需要锁,锁的太多,浪费资源
同步块
同步块:synchronized(Obj){ } Ojb称之为同步监视器
Ojb可以是任何对象,但是推荐使用共享资源作为同步监视器 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class
队列和锁
线程同步形成条件:队列+锁(每个对象都拥有一把锁)去解决线程不安全问题
死锁
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致这两个或多个线程都在等待对方释放资源,都停止执行的情形。某一同步块同时拥有“两个以上对象锁”时,就可能发生“死锁”的问题 产生死锁的必要条件:
互斥:一个资源只能被一个进程使用 请求和保持:一个进程因请求资源而阻塞时,对已获得的资源保持不放 不可剥夺:进程已获得资源,在未使用完之前,不能强行剥夺 循环等待:若干进程之间形成一种头尾相接的循环等待资源关系 注意:以上四个条件只要破坏一个或多个就可以避免死锁的发生
Lock锁
提供更强大的线程同步机制—通过显式定义同步锁对象来实现同步。同步锁使用Lock对象 充当 每次只能由一个线程对Lock对象加锁,线程开始访问共享资源之前应先去获得Lock对象 ReentrantLock(可重入锁 )类实现了Lock,比较常用,与synchronized的区别在于了显式的加锁、释放锁 Lock只能锁代码块
public class TestLock {
public static void main ( String [ ] args) {
Test test= new Test ( ) ;
new Thread ( test, "zs" ) . start ( ) ;
new Thread ( test, "ls" ) . start ( ) ;
new Thread ( test, "ww" ) . start ( ) ;
}
}
class Test implements Runnable {
private ReentrantLock Lock = new ReentrantLock ( ) ;
int num= 100 ;
boolean flag= true ;
public void buy ( ) throws InterruptedException {
if ( num< 1 ) {
flag= false ;
return ;
} else {
Thread . sleep ( 1000 ) ;
System . out. println ( Thread . currentThread ( ) . getName ( ) + "获得第" + num-- + "张票" ) ;
}
}
@Override
public void run ( ) {
while ( flag) {
try {
Lock . lock ( ) ;
buy ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
} finally {
Lock . unlock ( ) ;
}
}
}
}