`
赵雅智
  • 浏览: 97693 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

赵雅智_java 多线程(2)之线程同步

 
阅读更多

线程同步

package com.csdn;

class Tickets{
	public int tickets;
	public Tickets(){
		tickets = 10;
	}
}
public class SaleTicket {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Tickets t = new Tickets();
		Ticket st1 = new Ticket(t,"小王");
		Ticket st2 = new Ticket(t,"小张");
		
	}

}
class Ticket extends Thread {
	Tickets t;
	String name;
	public Ticket(Tickets t,String name){
		this.t = t;
		this.name = name;
		start();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0; i<5; i++){
			System.out.println(name+"抢到了第"+t.tickets+"票号");
			t.tickets--;
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}

package com.csdn;

public class SaleTickets {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SaleTicke st = new SaleTicke();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		t1.start();
		t2.start();
	}

}
class SaleTicke implements Runnable{
	private int tickets = 20;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			if(tickets>0){
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"......"+tickets--);
			}
		}
	}
	
}



为什么需要“线程同步” ??

线程间共享代码和数据可以节省系统开销,提高程序运行效率,但同时也导致了数据的“访问冲突”问题

如何实现线程间的有机交互、并确保共享资源在某些关键时段只能被一个线程访问,即所谓的“线程同步”(Synchronization)就变得至关重要。

临界资源: 多个线程间共享的数据称为临界资源(Critical Resource),

由于是线程调度器负责线程的调度,程序员无法精确控制多线程的交替顺序。因此,多线程对临界资源的访问有时会导致数据的不一致行。


互斥锁

每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。

关键字synchronized用来与对象的互斥锁联系

当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。

synchronized关键字的使用方式有两种:
1.同步代码块
synchronized(对象){

需要同步的代码
}


2.同步函数: 使用的锁是this

public synchronized void show(){

}

  1. 用在对象前面限制一段代码的执行(同步代码块)
    package com.csdn;
    
    class Tickets1{
    	public int tickets;
    	public Tickets1(){
    		tickets = 10;
    	}
    	
    }
    public class TestMulThread2{
         
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    	
    		Tickets1 t = new Tickets1();
    		Ticket1 st1 = new Ticket1(t,"小王");
    		Ticket1 st2 = new Ticket1(t,"小张");
    		
    	}
    
    }
    class Ticket1 extends Thread {
    	static String st1 ="aaa";
    	Tickets1 t;
    	String name;
    	public Ticket1(Tickets1 t,String name){
    		this.t = t;
    		this.name = name;
    		start();
    	}
    	public synchronized void show(){//同步代码块
    		System.out.println(name+"抢到了第"+t.tickets+"票号");
    		t.tickets--;
    	}
    	@Override
    	public void run() {
    			for(int i=0; i<5; i++){
    			synchronized(st1){
    			System.out.println(name+"抢到了第"+t.tickets+"票号");
    			t.tickets--;
    			}
    				//show();
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		
    		
    		}
    	}
    	
    }

    package com.csdn;
    
    public class SaleTicketsSy {
    		public static void main(String[] args) {
    			// TODO Auto-generated method stub
    			SaleTicketsy st = new SaleTicketsy();
    			Thread t1 = new Thread(st);
    			Thread t2 = new Thread(st);
    			t1.start();
    			t2.start();
    		}
    
    	}
    	class SaleTicketsy implements Runnable{
    		private int tickets = 100;
    		
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			Object obj = new Object();
    			while(true){
    				synchronized(obj){//同步代码块
    				if(tickets>0){
    					try {
    						Thread.sleep(20);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName()+"......"+tickets--);
    				}
    				}
    			}
    		}
    	}
    

  2. 用在方法声明中,表示整个方法为同步方法
    package com.csdn;
    
    public class TestMulThread {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Tickets2 t = new Tickets2();
    		TicketsThread d1 = new TicketsThread(t,"Jam");
    		TicketsThread d2 = new TicketsThread(t,"Jack");	
    	}
    }
    
    class Tickets2{
    	public int tickets;
    	public Tickets2(){
    		tickets = 10;
    	}
    	public synchronized void action(String name){//锁方法
    		System.out.println(name+"抢到了第"+tickets+"票号");
    		tickets--;
    	}
    }
    
    class TicketsThread extends Thread{
    	Tickets2 t;
    	String name;
    	public TicketsThread(Tickets2 t, String name){
    		this.t = t;
    		this.name = name;
    		start();
    	}
    	public void run(){
    		for(int i=0;i<5;i++){
    			t.action(name);
    			try {
    				Thread.sleep(20);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    package com.csdn;
    
    public class SaleTicketsSy2 {
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		SaleTicketsy2 st = new SaleTicketsy2();
    		Thread t1 = new Thread(st);
    		Thread t2 = new Thread(st);
    		t1.start();
    		t2.start();
    	}
    
    }
    class SaleTicketsy2 implements Runnable{
    	private int tickets = 100;
    	
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		while(true){
    			show();
    		}
    	}
    		public synchronized void show(){//锁方法
    			if(tickets>0){
    				try {
    					Thread.sleep(20);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				System.out.println(Thread.currentThread().getName()+"......"+tickets--);
    			}
    		}
    	}
    
    

同步好处:决了线程安全问题

同步弊端:降低了运行效率(判断锁是较为消耗资源的)

死锁:同步嵌套,容易出现死锁

死锁 两个线程A、B用到同一个对象s(s为共享资源),且线程A在执行中要用到B运行后所创造的条件。在这种前提下A先开始运行,进入同步块后,对象s被锁定,接着线程A因等待B运行结束而进入阻塞状态,于是B开始运行,但因无法访问对象s,线程B也进入阻塞状态,等待s被线程A解锁。最终的结果:两个线程互相等待,都无法运行。

package com.csdn;

public class DeadLock {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Demo6 d1=new Demo6(true);
		Demo6 d2=new Demo6(false);
		Thread t1=new Thread(d1);
		Thread t2=new Thread(d2);
		t1.start();
		t2.start();

	}

}

class MyLock{
	static MyLock lock1=new MyLock();
	static MyLock lock2=new MyLock();
	
}

class Demo6 implements Runnable{
	//String str1=new String("aaa");
	//String str2=new String("bbb");
	
	private boolean flag;
	public Demo6(boolean flag){
		this.flag=flag;
	}

	@Override
	public void run() {
		if(flag){
			synchronized(MyLock.lock1){
				System.out.println(Thread.currentThread().getName()+"...if...str1");	
				
				synchronized(MyLock.lock2){
					System.out.println(Thread.currentThread().getName()+"...if...str2");
					
				}
			}
			
			
		}else{
	         synchronized(MyLock.lock2){
	        	 System.out.println(Thread.currentThread().getName()+"...else...str2");
	        	
				 synchronized(MyLock.lock1){
					System.out.println(Thread.currentThread().getName()+"...else...str1");
				}
			}
		}
		
	}
	
}



分析:这是线程死锁的典型表现,两个以上线程并发运行,他们均因其他线程锁定了自己运行所需资源而陷入阻塞状态,同时自己也锁定了其他线程所需资源。

单例类

懒汉式

class Single{
private static Single s=null;
private Single(){}
public static Single getInstance(){
if(s==null)
synchronized(Singel。class){
if(s==null)
s=new Single();
}

return s;

}


class Single{
private static Single s=null;
private Single(){}
public static synchronized Single getInstance(){


if(s==null)
s=new Single();

return s;}
Single.getInstance();


饿汉式


class Single{
private static Single s=new Single();
private Single(){}
public static Single getInstance(){
return s;


}

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics