java基础专栏—ThreadSafe

ThreadSafe

多线程并发

public class Tickets implements Runnable{
    private int ticket = 100;
  	
  	public void run(){
        while(true){
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName() + "出售票" + ticket--);
            }
        }
    }
}
pubilc static void main(String[] args){
    Tickets ts = new Ticket();
  	
  	Thread t0 = new Thread(ts);
  	Thread t1 = new Thread(ts);
  	Thread t2 = new Thread(ts);
  
  	t0.start();
  	t1.start();
  	t2.start();
}

同步代码块解决线程问题:synchronized(Object obj){线程要操作的代码块}

private Object obj = new Object();
public void run(){
		while(true){
          	synchronized(obj){
               if(ticket > 0){
                System.out.println(Thread.currentThread().getName() + "出售票" + ticket--);
        	    } 
            }   
        }
	}

同步对象:任意对象,对象监听器

没有锁的线程不能执行只能等待,遇见同步代码块,

  • 判断对象锁还有没有
  • 有,拿走,等执行完成才放回去
  • 没有就只有等
  • 将线程共享部分抽取出来
private int ticket = 100;
public void run(){
		while(true){
          	pay();
            }   
        }
	}
public static synchronized void pay(){
	if(ticket > 0){]
                System.out.println(Thread.currentThread().getName() + "出售票" + ticket--);
}
//在同步方法中,对象锁是this。但是在静态方法中,对象锁不是this,this属于对象,优先于static,是本类自己.class

Lock

​ 在线程中,只有出了同步代码块才会释放对象锁,但是要是出现了异常就不会释放了。所以在jdk5以后就使用Lock接口

public void lock()

public void unlock()

死锁问题

锁的嵌套出现了互锁

  • 确保锁唯一
    • 构造方法私有,只能通过静态方法来调用,且不可修改
public class lockA{
  	public static final LockA lockA = new LockA(); 
  	
  	private LockA(){
      
  	}
}

public class lockB{
  	public static final LockB lockB = new LockB(); 
  	
  	private LockB(){
      
  	}
}

public class DeadLock implements Runnable{
    private int i = 0;
  
  	public void run(){
        while(ture){
            if(i%2 == 0){
                //先进入A同步,在进入B同步
              	synchronized(LockA.locka){
                    System.out.println("if...locka");
                  	synchronized(LockB.lockb){
                        System.out.println("else...lockb");
                    }
                }
            }else{
                synchronized(LockB.lockb){
                    System.out.println("if...lockb");
                  	synchronized(LockA.locka){
                        System.out.println("else...locka");
                    }
                }
            }
        }
    }
}

线程间通信

​ 多个线程操作同一个数据,但是操作的动作可能并不相同,通过一定的手段将各个线程有效的利用,既--等待唤醒机制

  • public void wait()释放正在执行的线程的执行权,放到存储池

  • public void notify()唤醒在线程池中wait()的线程,一次唤醒一个,而且是任意的。

  • public void notifyAll(),唤醒在线程池中所有的wait()线程唤醒

  • [x] 线程之间是不是所有的数据都锁上了

  • [x] 是不是用的同一个锁

    扫描二维码关注公众号,回复: 182350 查看本文章
public class Resource{
    public String name;
  	public String sex;
  	public boolean flag;//唤醒标识
  
  	public Resource(String name,String sex){
        this.name = name;
    }
}

public class InputThread implements Runnable{
    private Resource r = null;
  	public InputThread(Resource r){
        this.r = r;
    }
  	public void run(){
      	int i = 0; 
        while(true){
            synchronized(r){
              	if(r.flag){
                    try{
                      //必须是锁对象调用
                        r.wait();
                    }catch(Exception ex){
                        System.out.println(ex.getMessage());
                    }
                }
          		if(i%2 == 0){
                	r.name = "张三";
              		r.sex = "男";
            	}else{
                    r.name = "lisi";
              		r.sex = "nv";
                }
          	i++;
            //执行完成,将标识修改,并唤醒对方。
            r.flag = true;
            r.notify();
            }
        }
    }
}

public class OutputThread{
    private Resource r = null;
  	public void run(){
      //使用同一个对象锁
      	synchronized(r){
      		while(true){
              	if(r.flag){
                    try{
                      //必须是锁对象调用
                        r.wait();
                    }catch(Exception ex){
                        System.out.println(ex.getMessage());
                    }
            	System.out.println(r.name); 
                //执行完成,将标识修改,并唤醒对方。
                r.flag = false;
                r.notify();
        	}
        }
    }
  	public OutputThread(Resource r){
        this.r = r;
    }
}

public class ThreadDemo{
    public static void main(String[] args){
      	Resource r = new Resource();
        InputThread int = new InputThread(r);
      	OutputThread outt = new OutputThread(r);
		
      	Thread in = new Thread(in);
      	Thread out = new Thread(out);
    }
}

为什么是Object的方法

​ 对于线程来说,要同步必须操作同一个锁对象才可以,如果是使用各自来做自己的线程唤醒对象就不能实现同一个锁对象,并且对于实现类来说,调用者是谁?

​ ==所有的线程的等待唤醒必须是锁对象调用,调用者是谁?任何方法都需要被调用,本类线程类是没有wait方法的,只有调用父类的super(),但是父类也没有这个方法,调用这个的锁对象是谁就由谁来调用,所以,同步的等待唤醒方法都是Object类的方法==

猜你喜欢

转载自my.oschina.net/u/3483440/blog/1554402
今日推荐