java 同步锁 synchronized 死锁 lock锁 jion 线程结束

多个线程在操作共享的数据且操作共享数据的线程代码有多条。当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算。就会导致线程安全问题的产生。

同步代码块原理:将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程时不可以参与运算的。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。 

同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。

同步的前提:同步中必须有多个线程并使用同一个锁。

class Single
{
	private static Single s = null;
	private Single(){}
	
	public static Single getInstance()
	{
		if(s==null)
		{
			synchronized(Single.class)	 //这个用同一对象锁 只能创建一个对象	
			{
				if(s==null)
					s = new Single();
			}
		}
		return s;
	}
}

同步锁分为同步代码块锁、同步函数锁,同步函数的使用的锁是this;同步代码块的锁是任意的对象。使用最多的一般是同步代码块。

使用wait、notify、notifylAlll与同步锁配合的应用,wait()将线程添加到线程池中。notify释放本对象线程池中的任意一个线程,notifyAll释放本线程池中所有的线程

class Resource
{
	private String name;
	private int count = 1;
	private boolean flag = false;
	public synchronized void set(String name)//  
	{
		while(flag)   //唤醒时 重新判断flag  防止flag不符合也往下运行 
			try{this.wait();}catch(InterruptedException e){}  //在这里唤醒 醒后上面判断flag
		
		this.name = name + count;
		count++;
		System.out.println(Thread.currentThread().getName()+"."+this.name);
		flag = true;
		notifyAll();   //唤醒所有进程 防止 出现死锁 但是 唤醒所有锁 导致重新判断 效率下降了
	}

	public synchronized void out()
	{
		while(!flag)
			try{this.wait();}catch(InterruptedException e){}	
		System.out.println(Thread.currentThread().getName()+".........."+this.name);
		flag = false;
		notifyAll();
	}
}

class Producer implements Runnable
{
	private Resource r;
	Producer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.set("here");
		}
	}
}

class Consumer implements Runnable
{
	private Resource r;
	Consumer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}


class  ProducerConsumerDemo
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		t0.start();
		t1.start();
		t2.start();
		t3.start();

	}
}

同步锁如果操作不好会带来新问题:死锁。

线程a、线程b都一直在while(1)中运行,当线程a持有锁a要调用锁b时,如果此时cpu进行线程切换换到线程b,线程b运行,线程b持有锁b要调用锁a,结果发现,锁a被线程a持有没法调用就会等待系统调度切换到线程a,线程a继续运行要调用锁b,发现锁b被b线程持有,也没法运行,两者就形成了死锁。

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag = flag;
	}

	public void run()
	{
		
		if(flag)
		{
			while(true)
			    synchronized(MyLock.locka)    //同步锁a
			    {
			        System.out.println(Thread.currentThread().getName()+"1 locka.");
				synchronized(MyLock.lockb){	
				    System.out.println(Thread.currentThread().getName()+"1 lockb..");
				}
			    }
		}
		else
		{
			while(true)			
			    synchronized(MyLock.lockb)    //同步锁b
		            {
				System.out.println(Thread.currentThread().getName()+"2 lockb");
				synchronized(MyLock.locka)
				{
				    System.out.println(Thread.currentThread().getName()+"2 locka.");
				}
			    }
		}

	}

}

class MyLock     //锁对象
{
	public static final Object locka = new Object();     //a锁
	public static final Object lockb = new Object();     //b锁
}


class DeadLockTest 
{
	public static void main(String[] args) 
	{
		Test a = new Test(true);        
		Test b = new Test(false);       

		Thread t1 = new Thread(a);      //线程a
		Thread t2 = new Thread(b);      //线程b
		t1.start();
		t2.start();
	}
}


由于synchronized可能会导致死锁,而防止死锁的notifyAll释放所有进程,导致效率下降,java引入lock锁,Lock接口:替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。

同时更为灵活。可以一个锁上加上多组监视器。lock():获取锁。unlock():释放锁,通常需要定义finally代码块中。

import java.util.concurrent.locks.*;

class Resource
{
	private String name;
	private int count = 1;
	private boolean flag = false;

	Lock lock = new ReentrantLock();   //创建锁对象

	Condition producer_con = lock.newCondition();  //一把锁可以挂多个监视器
	Condition consumer_con = lock.newCondition();

	
	public  void set(String name)
	{
		lock.lock();   //上锁 
		try
		{
			while(flag)
			try{producer_con.await();}catch(InterruptedException e){}
		
			this.name = name + count;
			count++;
			System.out.println(Thread.currentThread().getName()+"."+this.name);
			flag = true;
			consumer_con.signal();   //激活消费者线程 这样就可以提高效率
		}
		finally
		{
			lock.unlock();  //解除锁
		}
		
	}

	public  void out()
	{
		lock.lock();
		try
		{
			while(!flag)
			try{cousumer_con.await();}catch(InterruptedException e){}	
			System.out.println(Thread.currentThread().getName()+"..."+this.name);
			flag = false;
			producer_con.signal();   //激活生产者线程
		}
		finally
		{
			lock.unlock();
		}
		
	}
}

class Producer implements Runnable
{
	private Resource r;
	Producer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.set("provide");
		}
	}
}

class Consumer implements Runnable
{
	private Resource r;
	Consumer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}



class  ProducerConsumerDemo2
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		t0.start();
		t1.start();
		t2.start();
		t3.start();

	}
}

在lock锁中,一个锁可以添加多个condition监视器,确保可以对指定线程进行操作,提高了运行效率,await()挂起线程 signal()恢复线程。


wait与sleep区别

1,wait可以指定时间也可以不指定。sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。

    wait:释放执行权,释放锁。sleep:释放执行权,不释放锁。


线程终止:控制循环通常就用定义标记来完成。如果线程处于了冻结状态,无法读取标记,

可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。 当强制动作会发生了InterruptedException,记得要处理

class StopThread implements Runnable
{
	private boolean flag = true;
	public synchronized void run()
	{
		while(flag)   //线程终止 标志
		{
			try
			{
				wait();
			}
			catch (InterruptedException e)  //interrupt强制唤醒 产生的异常
			{
				System.out.println(Thread.currentThread().getName()+"....."+e);
				flag = false;    
			}
			
			System.out.println(Thread.currentThread().getName()+"......++++");
		}
	}

}



class StopThreadDemo 
{
	public static void main(String[] args) 
	{
		StopThread st = new StopThread();

		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);

		t1.start();
		t2.setDaemon(true);  //守护线程 如果没有别的线程 会自动退出
		t2.start();

		int num = 1;
		for(;;)
		{
			if(++num==50)
			{
				t1.interrupt();
//				t2.interrupt();  //如果没设置为守护线程 需要这句话来 退出
				break;
			}
			System.out.println("main...."+num);
		}

		System.out.println("over");
	}
}

setDaemon()守护线程,必须在线程前开启前设置线程为守护线程,守护线程后台运行,当没有前台线程时,守护线程会自动结束然后结束jvm虚拟机。


jion()函数,线程挂起,直到该线程运行完,挂起此线程的线程才运行。

你可能感兴趣的:(java,synchronized,同步锁,死锁,Lock锁,线程结束)