您的位置:首页 > 编程语言 > Java开发

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

2014-09-13 00:00 483 查看
摘要: 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()函数,线程挂起,直到该线程运行完,挂起此线程的线程才运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息