线程的同步
描述一下一个线程从始至终的运行状态
(1)一个线程新建了,调用start()之后就进入就绪状态,等待cpu来调用他
(2)CPU调用到他了,如果他需要的资源足够,他就进入运行状态;在他运行的时候,随时有可能被CPU撤掉,收回他的资源,再次进入就绪状态;
在运行时,还有可能自己调用wait()方法或sleep()等,进入阻塞状态,这时他得释放掉自己占用的资源,等待sleep时间/被notify
如果代码都运行完毕就进入死亡状态了
判断是否存在线程安全的问题:
(1)是否有多个线程
(2)是否有多个线程操作同一个共享数据
(3)是否有多条语句与共享变量有关
1、同步代码块
synchronized(锁对象){
需要同步的代码
}
锁对象:
语法上,任意类型的对象都可以
几个相关的线程必须公用一把锁,这多个线程共享这一把锁
注意一次锁一个单元的任务,例如卖一张票的这个过程
如果是通过实现Runnable创建的线程的话,那就可以直接用this了,因为是同一个对象,所以锁对象也可以使用this了,共享的数据也不用必须用static修饰了,因为他们公用了一个线程代理
2、同步方法 直接对方法进行修饰
这样的话锁的就是整个方法了
非静态方法时,锁对象是this
静态方法时,锁对象是类名.class
当在对象上任意的synchronized方法的时候,对象都会被加锁,这个时候该对象的其他synchronize方法只有等到前一个方法调用完毕之后才能被调用。对于某个特定的对象来说,其所有的synchronize方法共享同一个锁,这样可以
关于线程的通信
设计到的方法
wait:等待
notify/notigyAll:通知
这些方法必须由锁对象来调用,这个锁对象是多个线程所共享的;
wait会让当前线程进入阻塞状态
notify会使当前线程从阻塞状态变回就绪状态
还有一种显示锁Lock
synchronized是JVM层面提供的锁,而Lock是Java语言层面jdk为我们提供的锁;这些锁都在java.util.concurrent包中
lock的加锁和释放都全部由我们控制,通常释放锁要在finally中实现
synchronized只有一个状态条件,就是每个对象只有一个监视器;如果需要多个Condition的组合,那么synchronized是无法满足的,而Lock则提供了多条件的互斥,更灵活
Lock和Condition
Lock lock = new ReentrantLock();//显示锁对象
lock.lock();//锁上
lock.unlock();//开锁
通信时
如果使用Lock锁,那么线程通信需要使用Condition解决
条件.await()//某种条件,等待
条件.signal()//某种条件,唤醒
Lock lock = new ReentrantLock();
Condition full = lock.newCondition();
Condition empty = lock.newCondition();
lock.lock();
full.await();
empty.signal();//signalAll()
lock.unlock();
empty.await();
full.singal();
关于单例模式需要注意的
懒汉式的时候:
public static Lazy getInstance(){
if(instance ==null){
synchronized(Lazy.class){
if(instance==null){
instance = new Lazy();
}
}
}
return instance;
}
多了一层的判断,时为了避免每次判断都得执行同步代码块消耗时间
描述一下一个线程从始至终的运行状态
(1)一个线程新建了,调用start()之后就进入就绪状态,等待cpu来调用他
(2)CPU调用到他了,如果他需要的资源足够,他就进入运行状态;在他运行的时候,随时有可能被CPU撤掉,收回他的资源,再次进入就绪状态;
在运行时,还有可能自己调用wait()方法或sleep()等,进入阻塞状态,这时他得释放掉自己占用的资源,等待sleep时间/被notify
如果代码都运行完毕就进入死亡状态了
判断是否存在线程安全的问题:
(1)是否有多个线程
(2)是否有多个线程操作同一个共享数据
(3)是否有多条语句与共享变量有关
1、同步代码块
synchronized(锁对象){
需要同步的代码
}
锁对象:
语法上,任意类型的对象都可以
几个相关的线程必须公用一把锁,这多个线程共享这一把锁
注意一次锁一个单元的任务,例如卖一张票的这个过程
如果是通过实现Runnable创建的线程的话,那就可以直接用this了,因为是同一个对象,所以锁对象也可以使用this了,共享的数据也不用必须用static修饰了,因为他们公用了一个线程代理
2、同步方法 直接对方法进行修饰
这样的话锁的就是整个方法了
非静态方法时,锁对象是this
静态方法时,锁对象是类名.class
当在对象上任意的synchronized方法的时候,对象都会被加锁,这个时候该对象的其他synchronize方法只有等到前一个方法调用完毕之后才能被调用。对于某个特定的对象来说,其所有的synchronize方法共享同一个锁,这样可以
关于线程的通信
设计到的方法
wait:等待
notify/notigyAll:通知
这些方法必须由锁对象来调用,这个锁对象是多个线程所共享的;
wait会让当前线程进入阻塞状态
notify会使当前线程从阻塞状态变回就绪状态
还有一种显示锁Lock
synchronized是JVM层面提供的锁,而Lock是Java语言层面jdk为我们提供的锁;这些锁都在java.util.concurrent包中
lock的加锁和释放都全部由我们控制,通常释放锁要在finally中实现
synchronized只有一个状态条件,就是每个对象只有一个监视器;如果需要多个Condition的组合,那么synchronized是无法满足的,而Lock则提供了多条件的互斥,更灵活
Lock和Condition
Lock lock = new ReentrantLock();//显示锁对象
lock.lock();//锁上
lock.unlock();//开锁
通信时
如果使用Lock锁,那么线程通信需要使用Condition解决
条件.await()//某种条件,等待
条件.signal()//某种条件,唤醒
Lock lock = new ReentrantLock();
Condition full = lock.newCondition();
Condition empty = lock.newCondition();
lock.lock();
full.await();
empty.signal();//signalAll()
lock.unlock();
empty.await();
full.singal();
关于单例模式需要注意的
懒汉式的时候:
public static Lazy getInstance(){
if(instance ==null){
synchronized(Lazy.class){
if(instance==null){
instance = new Lazy();
}
}
}
return instance;
}
多了一层的判断,时为了避免每次判断都得执行同步代码块消耗时间