----------------------
ASP.Net+Android+IOS开发、
.Net培训、期待与您交流! -----------------
Java对于多线程的安全问题提出的解决方法:同步代码块。
synchronized(对象){ //这里的对象不重要,它只是提供一个标志位,相当于一个锁。可用Object的对象
需要被同步的代码块(对共享资源的操作)
}
也可以直接同步一个函数,即把synchronized作为修饰符放在函数声明处就可以了。函数加锁后,函数的锁是this对象,所以如果此加锁非静态函数要是和别的同步代码块同步的话,那么要加一样的锁,同步代码块的参数要用this。
同步的前提:1必须要有两个或者以上的线程。
2必须是多线程使用同一个锁
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源
如果同步函数被静态修饰后,使用的锁是该类进内存时该类的字节码文件对象,类名.class 该对象的类型是class。
所以如果此加锁静态函数要是和别的同步代码块同步的话,那么要加一样的锁,同步代码块的参数要用 类名.class。
懒汉式单例应用(延迟加载单例):
这里用双重判断来提高效率,免得所有的进程来都要判断是否上锁。
这个例子中,t1 ,t2就会产生死锁。当t2刚进入show方法获取show方法的锁(为t2对象本身)且还没有获得obj锁时,cpu执行t1,这时假设t1拿到obj锁且正要执行show方法,那么就会产生死锁了。t1此时需要得到t2对象这个锁,但是这个锁被t2占有,t2此时需要得到obj这个锁,但是obj又被t1占有,所以两者僵持,就产生了死锁。
因为这些方法在操作同步中线程时i,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。不可以对不同锁中的线程唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以对锁操作的方法要定义在Object类中。
注意:wait()方法是让线程无终止冻结,交出锁和cpu
Lock接口和Condition接口:JDK1.5 中提供了多线程升级解决方案。将同步synchronized替换成现实lock操作。将Object中的wait notify notifyAll 替换成了Condition对象。该对象可以对Lock锁进行获取。
private Lock lock=new ReentrantLock();实现Lock对象。
lock.lock();加锁
lock.unlock();释放锁对象。建议放在finally{}中。
private Condition condition=lock.newCondition();实现Condition对象。
condition.await();//挂起
condition.signal();//唤醒一个线程
condition.signalAll();//唤醒其他所有线程
如果想唤醒多个线程中的某一个或几个线程,可以通过实例化多个Condition对象,为指定线程分配指定的对象即可。
如多个生产者和多个消费者,就可以给生产者实例化一个condition对象,给消费者实例化一个condition对象。程序中用指定对象的signal方法即可。
如何停止线程
开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:当线程处于冻结状,就不会读取到标记,那么线程就不会结束。就当没有指定方法让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。Thread类提供了interrupt()方法,即是让此线程从冻结状态恢复到运行状态。
Java对于多线程的安全问题提出的解决方法:同步代码块。
synchronized(对象){ //这里的对象不重要,它只是提供一个标志位,相当于一个锁。可用Object的对象
需要被同步的代码块(对共享资源的操作)
}
也可以直接同步一个函数,即把synchronized作为修饰符放在函数声明处就可以了。函数加锁后,函数的锁是this对象,所以如果此加锁非静态函数要是和别的同步代码块同步的话,那么要加一样的锁,同步代码块的参数要用this。
同步的前提:1必须要有两个或者以上的线程。
2必须是多线程使用同一个锁
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源
如果同步函数被静态修饰后,使用的锁是该类进内存时该类的字节码文件对象,类名.class 该对象的类型是class。
所以如果此加锁静态函数要是和别的同步代码块同步的话,那么要加一样的锁,同步代码块的参数要用 类名.class。
懒汉式单例应用(延迟加载单例):
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;
}
这里用双重判断来提高效率,免得所有的进程来都要判断是否上锁。
死锁:同步中嵌套同步
package com.itheima;
class Ticket2 implements Runnable{
Object obj=new Object();
private String name;
private static int ticket=200;
boolean flag=true;
public void run(){
if(flag){
while(true){
synchronized(obj){
System.out.print("if+"+Thread.currentThread().getName());
show();
}
}
}
else{
while(true){
System.out.print("else+++"+Thread.currentThread().getName());
show();
}
}
}
public synchronized void show(){
synchronized(obj){
if(ticket>0){
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"show--------"+ticket--);
}
}
}
}
public class DeadLockTest1 {
public static void main(String[]args){
Ticket2 tic=new Ticket2();
Thread t1=new Thread(tic);
Thread t2=new Thread(tic);
t1.start();
try{
Thread.sleep(10);}
catch(Exception e){}
tic.flag=false;
t2.start();
}
}
这个例子中,t1 ,t2就会产生死锁。当t2刚进入show方法获取show方法的锁(为t2对象本身)且还没有获得obj锁时,cpu执行t1,这时假设t1拿到obj锁且正要执行show方法,那么就会产生死锁了。t1此时需要得到t2对象这个锁,但是这个锁被t2占有,t2此时需要得到obj这个锁,但是obj又被t1占有,所以两者僵持,就产生了死锁。
wait(),notify(),notifyAll() 都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才具有锁。使用方法: 锁.wait 锁.notify() 锁.notifyAll()
为什么这些操作线程的方法要定义在Object类中呢?因为这些方法在操作同步中线程时i,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。不可以对不同锁中的线程唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以对锁操作的方法要定义在Object类中。
注意:wait()方法是让线程无终止冻结,交出锁和cpu
Lock接口和Condition接口:JDK1.5 中提供了多线程升级解决方案。将同步synchronized替换成现实lock操作。将Object中的wait notify notifyAll 替换成了Condition对象。该对象可以对Lock锁进行获取。
private Lock lock=new ReentrantLock();实现Lock对象。
lock.lock();加锁
lock.unlock();释放锁对象。建议放在finally{}中。
private Condition condition=lock.newCondition();实现Condition对象。
condition.await();//挂起
condition.signal();//唤醒一个线程
condition.signalAll();//唤醒其他所有线程
如果想唤醒多个线程中的某一个或几个线程,可以通过实例化多个Condition对象,为指定线程分配指定的对象即可。
如多个生产者和多个消费者,就可以给生产者实例化一个condition对象,给消费者实例化一个condition对象。程序中用指定对象的signal方法即可。
class Resource{
private String name;
private int count=1;
private boolean flag=false;
private Lock lock=new ReentrantLock();
private Condition condition_pro=lock.newCondition();
private Condition condition_con=lock.newCondition();
public void set(String name){
while(flag){
lock.lock();
while(flag)
try {
condition_pro.await();//挂起自己这个生产者进程
this.name=name+"---"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
flag=true;
condition_con.signal();//唤醒一个消费者进程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
lock.unlock();
}
}
}
public void out(){
while(!flag){
lock.lock();
try {
condition_con.await();//挂起自己这个消费者进程
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag=true;
condition_pro.signalAll();//唤醒一个生产者进程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
lock.unlock();
}
}
}
}
class Consumer implements Runnable{
private Resource r;
public Consumer(Resource r){
this.r=r;
}
public void run(){
while(true)
r.out();
}
}
class Producer implements Runnable{
private Resource r;
public Producer(Resource r) {
this.r=r;
}
public void run(){
while(true)
r.set("+商品+");
}
}
public class ProducerConsumerDemo {
public static void main(String[]args){
Resource res=new Resource();
Consumer a=new Consumer(res);
Producer b=new Producer(res);
Thread t1=new Thread(a);
Thread t2=new Thread(b);
Thread t3=new Thread(a);
Thread t4=new Thread(b);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
如何停止线程
开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:当线程处于冻结状,就不会读取到标记,那么线程就不会结束。就当没有指定方法让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。Thread类提供了interrupt()方法,即是让此线程从冻结状态恢复到运行状态。
class StopThread implements Runnable{
private boolean flag=true;
public synchronized void run(){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+".......Exception");
ChangeFlag();
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void ChangeFlag(){
this.flag=false;
}
}
public 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.start();
int num=0;
while(true){
if(num++==60){
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"...main..."+num);
}
System.out.println("over");
}
}
join:当A线程执行到了B线程的join方法时,那么A线程就会等待,等到B线程都执行完,A才会执行。join用来临时加入线程执行。