博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 同步锁 synchronized 死锁 lock锁 jion 线程结束
阅读量:6891 次
发布时间:2019-06-27

本文共 6109 字,大约阅读时间需要 20 分钟。

hot3.png

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

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

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

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

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()函数,线程挂起,直到该线程运行完,挂起此线程的线程才运行。

转载于:https://my.oschina.net/u/274829/blog/313162

你可能感兴趣的文章
利用php创建数据库练习,注册
查看>>
关于jquery事件动态绑定(on的使用)
查看>>
Rancher推出k3OS:业界首个Kubernetes操作系统,领跑边缘计算生态
查看>>
awk sed grep 正则表达式
查看>>
Python学习第七天
查看>>
安装centos7
查看>>
MySQL 分析服务器状态
查看>>
Linux基础命令
查看>>
Tomcat日志
查看>>
linux基础篇-文本三剑客之AWK
查看>>
DNS服务原理及区域解析库文件配置
查看>>
OneinStack一键安装LNAMP环境
查看>>
python操作mysql数据库
查看>>
学习四十四
查看>>
ITSM选型关键要素(二)——如何对待个性化需求?作者:谭友吉
查看>>
iperf测试网卡性能
查看>>
企业如何确保精益生产管理真正落地?
查看>>
@Scheduled cronExpression表达式
查看>>
关于车牌识别的工作原理和技术参数
查看>>
放射科医生可零门槛调用AI算法:美国放射学会发布人工智能开放平台
查看>>