双重检测double checking
多用锁块,少用方法锁
package TCPUDPThread;
/**
* 抢票
*
* 线程同步
* 并发控制:synchronized
*
* 准确性:线程安全
*
* 线程不安全:数据有负数/相同
*
* 队列与锁
* 并发:同一个对象多个线程同时操作
*
* 线程同步
* 由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了
* 访问冲突的问题.为了保证数据在方法中被访问时的正确性,在访问时加入
* 锁机制(synchronized),当一个线程获得对象的排它锁,独占资源,其他线程
* 必须等待,使用后释放锁即可.存在以下问题:
* 一个线程持有锁会导致其他所有需要此锁的线程挂起;
* 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
* 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题.
*
* 由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们
* 只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:
* synchronized方法和synchronized块.
*
* 同步方法
* publci synchronized void method(int args){}
*
* synchronized方法控制对"成员变量|类变量"对象的访问:每个对象对应一把锁,每个
* synchronized方法都必须获得调用该方法的对象的锁方能执行,否则所属线程阻塞,方法
* 一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,
* 重新进入可执行状态。
*
* 缺陷:若将一个大的方法声明为synchronized将会大大影响效率.
*
* 锁对象,操作成员方法锁this,静态方法锁class对象
*
* 线程同步的难点:①数据安全准确 ②性能
*
* ①目标要对
* ②效率要高
*
* 线程安全:在并发时保证数据的正确性,效率尽可能高
* synchronized
* 1.同步方法
* 2.同步块
* @author pmc
*
*/
public class synchronizedTest4 {
public static void main(String[] args){
Webss12306 we=new Webss12306();
new Thread(we,"*1*").start();
new Thread(we,"*2*").start();
new Thread(we,"*3*").start();
}
}
class Webss12306 implements Runnable {
//票数
private int p=10;
private boolean flag=true;
@Override
public void run() {
while(flag){
test4();
}
}
//锁块
private void test(){
/**
* 线程安全
* this包装当前Webss12306对象
*/
synchronized(this){
if(p<=0){
flag=false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+p--);
}
}
private synchronized void test1(){
/**
* 线程安全
*/
if(p<=0){
flag=false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+p--);
}
private void test2(){
/**
* 线程不安全
* p是变动的所以锁不住
* */
synchronized((Integer)p){
if(p<=0){
flag=false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+p--);
}
}
private void test3() {
/**
* 线程不安全 p是变动的所以锁不住
*/
synchronized (this) {
if (p <= 0) {
flag = false;
return;
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->" + p--);
}
/**
* 线程安全
* 尽可能锁定合理的范围(不是指代码,指数据的完整性)
* 双重检查double checking
*
* 多使用块,少用方法
* */
private void test4(){
if(p<=0){//考虑没有票的情况
flag=false;
return;
}
synchronized(this){
if(p<=0){//考虑最后一张票
flag=false;
return;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+p--);
}
}
}