黑马程序员_多线程2

-----------------------------------------------------------------android培训java培训、期待与您交流! ---------------------------------------------------------------

1.      多线程的安全问题:synchronized(同步问题)

①      多线程同步代码块

②      多线程同步函数 :同步关键字作为修饰符修饰函数

同步代码块:

synchronized(对象)

{

       需要被同步的代码

}

同步的前提(重要)

1.      必须有两个或两个以上线程

2.      必须是多个线程使用同一个锁

同步代码块弊端:因为线程每次都要对锁进行判断,比较消耗资源(该消耗在使用允许范围内)

 

同步函数

当synchronized修饰函数时,并没有指定锁,其默认的锁为this

如果同步函数被static静态修饰时,因为静态方法中还没有this(即还没有对象),静态进内存中还没有本类对象,但是一定有该类对应的字节码文件对象-----即:类名.class 该对象的类型是Class,使用可以使用该类对象.clsss文件为锁

 

懒汉式的安全问题

//饿汉式
class Single {
	private static final Single s = new Single();
	private Single(){}
	public static Single getInstance() {
		return s;
	}
}
因为饿汉式在开始时就已经创建了Single实例,所以并不会出现多线程的安全问题

//懒汉式---存在多线程安全问题
class Single {
	private static Single s = null;
	private Single() {}
	public static Single getInstance() {
		if(s == null)
			s = new Single();
		return s;
	}
}
在多线程情况下,判断single对象是否存在时就有安全隐患所以需要加锁同步

//懒汉式安全方法
class Single {
	private static Single s = null;
	private Single() {}
	public static Single getInstance() {
		if(s == null) {		
			synchronized(Single.class) {//静态方法的锁没有this,使用该类所属的字节码文件对象作为锁
				if(s == null)
					s = new Single();
			}
		}
		return s;
	}
}

线程通信同步安全问题

/*
线程通信优化
*/
class Res {
	
	private String name;
	private String sex;	
	private	boolean flag = false;

	public synchronized void set(String name, String sex) {
		if(flag)
			try{this.wait();}catch(Exception e) {}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();			
	}

	public synchronized void out() {
		if(!flag)
			try{this.wait();}catch(Exception e) {}
		System.out.println(this.name + "=============" + this.sex);
		flag = false;
		this.notify();
	}	

}

class Output implements Runnable {
	Res r;
	Output(Res r) {
		this.r = r;
	}
	public void run() {
		while(true) {
			r.out();	
		}
	}
}

class Input implements Runnable {
	Res r;
	Input(Res r) {
		this.r = r;
	}
	public void run() {
		int x = 0;
		while(true) {
				if(x == 0) 			
					r.set("Tom", "man");
				else
					r.set("丽丽", "女女女女女女");
			x = (x + 1) % 2;
		}
	}
}

class InputOutputDemo2 {
	public static void main(String[] args) {
		Res r = new Res();
		Input in = new Input(r);
		Output out = new Output(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		t1.start();
		t2.start();
	}
}
在两个线程通信时,使用同步共享资源后通过等待和唤醒完成了线程通信

线程通信共享问题----等待唤醒机制

      wait()

      notify()

      notifyAll()

wait()与notify(),notifyAll()----并不是Tread类中的,而是其父类Object里的,且该三个方法一般用于同步代码中----并且需要标识其对应的锁

为什么该三个方法定义在Object类中呢?

因为当你在同步代码时要标识他们所操作线程所操作的锁,而这个锁不一定唯一可以是任意对象,所以放在所有类的父类Object。


多个生产者消费者同步共享安全问题---------while循环和notifyAll()

当多个线程操作共享数据时通过上边的两个线程通信if判断标识,notify唤醒线程会出现安全问题所以需改进代码

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

	public synchronized void set(String name) {
		while(flag)//if改用while循环判断
			try{this.wait();}catch(Exception e) {}
		this.name = name + "=====" + count++;
		System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name);
		flag = true;
		this.notifyAll();//唤醒等待队列的所有线程
	}

	public synchronized void out() {
		while(!flag)//if改用while循环判断
			try{this.wait();}catch(Exception e) {}
		System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name);
		flag = false;
		this.notifyAll();//唤醒等待队列的所有线程

	}

}
class Producer implements Runnable {
	private Resource r;
	Producer(Resource r){
		this.r = r;
	}

	public void run () {	
		while(true) {
			r.set("Product : Tool");
		}
	}
}

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 producer = new Producer(r);
		Consumer consumer = new Consumer(r);

		Thread proThread1 = new Thread(producer);
		Thread proThread2 = new Thread(producer);

		Thread conThread1 = new Thread(consumer);		
		Thread conThread2 = new Thread(consumer);
		
		proThread1.start();		
		proThread2.start();

		conThread1.start();		
		conThread2.start();		

	}
}

多个生产者消费者同步共享JDK1.5 新特性---------java.util.concurrent.locks---Lock接口----Condition接口

Lock接口替代synchronized

Condition接口替代Object的wait,notify,notifyAll-----------使用方法await,signal,signalAll

Lock接口三个实现类

       |--ReentrantLock

       |--ReentrantReadWriteLock.ReadLock

       |--ReenttrantReadWriteLock.WriteLock

用JDK1.5的Lock锁改动多个线程同步的代码

//这只是对原来代码的改用并没有用到新的特点
import java.util.concurrent.locks.*;
class Resource {
	private String name;
	private int count = 1;
	private boolean flag = false;

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

	private Condition condition = lock.newCondition();
	public void set(String name) throws InterruptedException {
		lock.lock();
		try {	
			while(flag)
				//try{this.wait();}catch(Exception e) {}
				condition.await();
			this.name = name + "=====" + count++;
			System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name);
			flag = true;
			//this.notifyAll();
			condition.signalAll();
		} finally {//因为锁是资源最后一定要释放
			lock.unlock();
		}
	}

	public void out() throws InterruptedException{
		lock.lock();
		try {
			while(!flag)
				//try{this.wait();}catch(Exception e) {}
				condition.await();
			System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name);
			flag = false;
			//this.notifyAll();
			condition.signalAll();
		} finally {
			lock.unlock();
		}
	}

}
class Producer implements Runnable {
	private Resource r;
	Producer(Resource r){
		this.r = r;
	}

	public void run () {	
		while(true) {
			try {
				r.set("Product : Tool");
			} catch(InterruptedException e) {

			}
		}
	}
}

class Consumer implements Runnable {
	private Resource r;
	Consumer(Resource r){
		this.r = r;
	}

	public void run() {	
		while(true) {
			try {
				r.out();
			} catch(InterruptedException e) {

			}
		}
	}
}
class ProducerConsumerJDKenhanceDemo {
	public static void main(String[] args) {
		Resource r = new Resource();

		Producer producer = new Producer(r);
		Consumer consumer = new Consumer(r);

		Thread proThread1 = new Thread(producer);
		Thread proThread2 = new Thread(producer);

		Thread conThread1 = new Thread(consumer);		
		Thread conThread2 = new Thread(consumer);
		
		proThread1.start();		
		proThread2.start();

		conThread1.start();		
		conThread2.start();		

	}
}

await与signal 不同于wait与notify

await可以等待指定的condition

signal可以唤醒指定的condition

所以新版本的Lock实现同步代码如下

import java.util.concurrent.locks.*;
class Resource {
	private String name;
	private int count = 1;
	private boolean flag = false;

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

	private Condition conditionProducter = lock.newCondition();
	private Condition conditionConsumer = lock.newCondition();
	public void set(String name) throws InterruptedException {
		lock.lock();
		try {	
			while(flag)
				//try{this.wait();}catch(Exception e) {}
				conditionProducter.await();
			this.name = name + "=====" + count++;
			System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name);
			flag = true;
			//this.notifyAll();
			conditionConsumer.signal();
		} finally {//因为锁是资源最后一定要释放
			lock.unlock();
		}
	}

	public void out() throws InterruptedException{
		lock.lock();
		try {
			while(!flag)
				//try{this.wait();}catch(Exception e) {}
				conditionConsumer.await();
			System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name);
			flag = false;
			//this.notifyAll();
			conditionProducter.signal();
		} finally {
			lock.unlock();
		}
	}

}
class Producer implements Runnable {
	private Resource r;
	Producer(Resource r){
		this.r = r;
	}

	public void run () {	
		while(true) {
			try {
				r.set("Product : Tool");
			} catch(InterruptedException e) {

			}
		}
	}
}

class Consumer implements Runnable {
	private Resource r;
	Consumer(Resource r){
		this.r = r;
	}

	public void run() {	
		while(true) {
			try {
				r.out();
			} catch(InterruptedException e) {

			}
		}
	}
}
class ProducerConsumerJDKenhanceDemo2 {
	public static void main(String[] args) {
		Resource r = new Resource();

		Producer producer = new Producer(r);
		Consumer consumer = new Consumer(r);

		Thread proThread1 = new Thread(producer);
		Thread proThread2 = new Thread(producer);

		Thread conThread1 = new Thread(consumer);		
		Thread conThread2 = new Thread(consumer);
		
		proThread1.start();		
		proThread2.start();

		conThread1.start();		
		conThread2.start();		

	}
}


停止线程


原有的stop方法已经过时,如何停止线程?

只有一种方法,run方法结束。

开启多线程运行,运行代码通常是循环结构,只要控制循环,就可以让run方法结束,也就是线程结束。

代码操作----在循环中使用boolean型标记,对外提供一个修改标记方法

特殊情况:

多线程中当线程冻结时,不会读到标记,线程就无法停止

如何解决这个问题?

interrupt对冻结状态清除,强制让线程回复到运行状态中,这样就可以修改标记,让线程结束

 

守护线程(后台线程)

setDanmon()设置成守护线程---必须在线程启动前设置

 

join方法

当A线程执行到了B线程的join方法时,A线程等待,等B线程执行完,A才会执行

Join可以临时加入线程

 

线程优先级----1---10

默认优先级5

可以通过setPriority()设置线程优先级

MAX_PRIORITY

MIN_PRIORITY

NORM_PRIORITY

 

yield(): 暂停当前正在执行的线程对象,并执行其他线程。


你可能感兴趣的:(多线程,安全,JDK1.5)