黑马程序员----Java多线程

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


1.概念:

进程:进行中的程序

线程:进程中不同的进行流程(执行路径)

多线程的好处:解决了多部分代码同时运行的问题。

弊端:CPU的切换会导致效率变低。


2.创建线程的两种方式

1)implements Runnable :实现接口,避免了单继承造成的局限性

2)Extends Thread :继承父类

示例:

买票问题。如果采用Extends Thread类来实现,要把票数Num定义成静态字段,造成效率的降低,这时候采用implements Runnable的方式就可以将票数定义成非静态字段。

package com.cn.test;
/**
 * 卖票系统例子区分两种线程创建方式
 * 实现方式比继承方式避免了单继承的局限性
 */
class MyThread extends Thread{//继承方式创建
	private static int num=1000;//卖票数得静态化
    @Override
	public void run() {
    	while(true){
    		if(num>0){
    			Thread.yield();
    			System.out.println(Thread.currentThread().getName()+"@@@@@@@"+num--);
    		}
    		
    	}
	}	
}
class MyRunnable implements Runnable{
	private int num=1000;//实现接口方式,因为共用了一个对象产生线程,所以Num字段不用静态化
	public void run() {
    	while(true){
    		if(num>0){
    			Thread.yield();
    			System.out.println(Thread.currentThread().getName()+"@@@@@@@"+num--);
    		}
    		
    	}
	}
}
public class ConstructTest {
	public static void createByEtds(){//通过继承Threads类创建对象
		MyThread mt1=new MyThread();
		MyThread mt2=new MyThread();
		mt1.start();
		mt2.start();
		
	}
	public static void createByIpl(){//实现方式创建
		MyRunnable mr1=new MyRunnable();
		new Thread(mr1).start();
		new Thread(mr1).start();
		new Thread(mr1).start();
		new Thread(mr1).start();
	}

	public static void main(String[] args) {
//		createByEtds();//继承方式
		createByIpl();//实现方式
	}

}



3.线程的安全问题

上述例子会产生零票数与负票数的情况


这是因为在某个线程在执行到Num字段的判断时,cpu的执行权被其他线程抢走,这时候Num字段由于不受保护,会被多线程修改。从而出现了0,-1,-2的情况。

线程安全问题产生的原因:多个线程共享未被保护的数据。解决的办法:给共享资源上一把锁,哪个线程要用,哪个线程拿锁进去用。类比:火车上的卫生间。

同步代码块与同步函数能解决这个问题。

关键字:synchronizied

package com.cn.test;
/**
 * 为了演示synchronized函数与代码块的区别,添加了flag
 * 同步要两个前提:有两个或以上线程,用的是同一个锁

 */
class TicketThread implements Runnable {
	private int num = 1000;
	public boolean flag = true;
	public void run() {
		if (flag) {
			while (true) {
				synchronized (this) {//同步代码块相当于一把线程锁,保证资源安全
					if (num > 0) {
						try {
							Thread.sleep(10);
						} catch (Exception e) {
							// TODO: handle exception
						}
						System.out.println(Thread.currentThread().getName()
								+ "@@@@@code" + num--);
					}
				}
			}
		} else {
			while (true) {
				show();
			}
		}

	}

	private synchronized void show() {//synchronized修饰的函数,锁的对象是this指针
		if (num > 0) {
			try {
				Thread.sleep(10);
			} catch (Exception e) {
				// TODO: handle exception
			}
			System.out.println(Thread.currentThread().getName() + "@@@@@show"
					+ num--);
		}

	}
}

public class SynchronizedDemo {
	public static void main(String[] args) {
		TicketThread th=new TicketThread();
		new Thread(th).start();
		try{Thread.sleep(10);}catch (Exception e) {e.printStackTrace();}//第一个线程启动后sleep(10),让后面的线程启动
		th.flag=false;
		new Thread(th).start();
	}
}

静态同步代码块用的是改函数所属的字节码文件,即对象.getClass()或类.class()

4.死锁

不同线程相互持有其锁,导致程序不能继续进行


package com.cn.test;
/**
 * 死锁

 */
class MyDeadLock implements Runnable{
	private boolean flag=true;
	MyDeadLock(boolean flag){
		this.flag=flag;
	}
	
	public void run(){
		if(flag){
			while(true){
				synchronized(Locked.lock1){//同时持有两把锁
					System.out.println(Thread.currentThread().getName()+"lock1");
					synchronized(Locked.lock2){//第二把锁
						System.out.println(Thread.currentThread().getName()+"lock2");
					}
				}
			}
			
		}
		else {
			while(true){
				synchronized(Locked.lock2){//第二个线程持有第一个线程的锁
					System.out.println(Thread.currentThread().getName()+"lock2");
					synchronized(Locked.lock1){
						System.out.println(Thread.currentThread().getName()+"lock1");
					}
				}
			}
			
		}
	}
	
}
class Locked{
	public static final Object lock1=new Object();
	public static final Object lock2=new Object();
}
public class DeadLock {
	public static void main(String[] args) {
		MyDeadLock ml1=new MyDeadLock(true);
		MyDeadLock ml2=new MyDeadLock(false);
		new Thread(ml1).start();
		try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}
		new Thread(ml2).start();
	}
}



5.线程的生命周期


主要涉及方法:sleep(),wait(),notify(),notifyAll()


例子:生产者与消费者

交替的处理机制:首先立flag=false;没有就让消费者wait,转到生产者,生产者++

再改flag.再唤醒,

flag=false

|--if(flag) flag=true;生产者

|--if(flag) flag=false;消费者

由于多个生产者/消费者时用notify出问题,改用notifyAll

package com.cn.test;

class Person {
	private String name;
	private String gender;
	private boolean flag = false;//作为交替,设立flag
	private int num=1;
	public synchronized void set(String name, String gender) {
		if (flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name;
		this.gender = gender;
		
		num++;
		System.out.println(Thread.currentThread().getName()+"生产者"+num);
		flag = true;
		this.notifyAll();
		
	}

	public synchronized void get() {
		
		if (!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		num--;

		System.out.println(Thread.currentThread().getName()+"消费者@@"+this.num);
		flag = false;
		this.notifyAll();
	}
}

class Input implements Runnable {
	Person p;
	Input(Person p) {
		this.p = p;
	}
	public void run() {
		int x = 0;// -------------------循环存
		while (true) {
			if (x == 0) {
				p.set("zhangsan", "nan");
			} else
				p.set("XIAOHONG", "NV");
			x = (x + 1) % 2;

		}
	}
}

class Output implements Runnable {
	Person p;

	Output(Person p) {
		this.p = p;
	}

	public void run() {
		while (true) {
			p.get();
		}
	}
}

public class MutilpDemo {
	public static void main(String[] args) {
		Person p = new Person();//初始化资源
		Input in1 = new Input(p);//生产者1线程
		Input in2 = new Input(p);//生产者2线程
		Output out1 = new Output(p);//消费者1线程
		Output out2 = new Output(p);//消费者2线程
		Thread t1 = new Thread(in1);
		Thread t2 = new Thread(in1);
		Thread t3 = new Thread(out1);
		Thread t4 = new Thread(out1);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}


7.JDK1.5以后的新特性

Lock lock=new ReentrantLock();

condition conXX=lock.newCondition()

wait -> conXX.await

notify-> conXX.sign

package com.cn.test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Sourse{
	private String name;//资源名称
	private int num;//资源数量
	private boolean flag=false;//交替旗帜
	Lock lock=new ReentrantLock();//新的锁
	Condition conPro=lock.newCondition();//能根据不同条件notify(signal)
	Condition conCut=lock.newCondition();
	public void produce(){
		lock.lock();
		try {
			if(flag){
				try {
					conPro.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			this.name="货物"+num;
			this.num++;		
			System.out.println("Sheng生产者"+Thread.currentThread().getName()+this.name);
			flag=true;
			conCut.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			lock.unlock();//要释放锁
		}
	}
	public void custom(){
		lock.lock();
		try {
			if(!flag){
				try {
					conCut.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			this.name="货物"+num;
			this.num--;		
			System.out.println("消费者"+Thread.currentThread().getName()+this.name);
			flag=false;
			conPro.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			lock.unlock();
		}
	}
}
class setTread implements Runnable{
	private Sourse s;
	setTread(Sourse s){
		this.s=s;
	}
	public void run() {
		while(true){
			s.produce();
		}
	}
}
class getTread implements Runnable{
	private Sourse s;
	getTread(Sourse s){
		this.s=s;
	}
	public void run() {
		while(true){
			s.custom();;
		}
	}
}
public class For15Demo {
	public static void main(String[] args) {
		Sourse s=new Sourse();
		setTread s1=new setTread(s);
		setTread s3=new setTread(s);
		getTread s2=new getTread(s);
		getTread s4=new getTread(s);
		new Thread(s1).start();
		new Thread(s2).start();
		new Thread(s3).start();
		new Thread(s4).start();
	}
}



8.其他补充

.interrupt()强制唤醒线程,会抛InterruptedException异常

setPriority(0~10)设置优先级

setDeamXX设置守护线程,在jvm运行环境里只剩下守护线程时,程序结束

join()强行并线


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值