栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程之线程高级

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程之线程高级

1.生产者消费者模型

技术点:
        多线程模型,安全锁机制,等待与唤醒 

public class Test1 {
	public static void main(String[] args) {
		Store store = new Store();
		new Producter(store).start();
		new Customer(store).start();
		
		//多个生产者和消费者线程
		new Producter(store).start();
		new Customer(store).start();
	}
}

-----生产者-----
public class Producter extends Thread {
	private Store store;
	public Producter(Store store){  //库存要存进来
		this.store = store;
	}
	@Override
	public void run() {
		while(true) {
			try {
				store.push();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}  //生产者负责生产
		}
	}
}

----消费者----
public class Customer extends Thread {
	private Store store;
	public Customer(Store store) {
		this.store = store;
	}
	@Override
	public void run() {
		while(true) {
			try {
				store.pop();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}  //消费者负责消费
		}
	}
}

---库存---
public class Store {
	private int num;  //单位万
	
	public void push() throws InterruptedException {  //库存生产
		
		synchronized (this) {
			//生产20件货,就满了,停止生产
			while(num>=20) {
				this.wait();
			}
			
			num++;
			System.out.println("生产者已经生产了第"+num+"件货");
			
			this.notify();  //唤醒等待的线程
		}
		
	}
	
	public void pop() throws InterruptedException {  //库存消费
		synchronized (this) { //
			while(num<=0) {
				this.wait();  //等待消费,等待时,相当于把自身资源交出去了
			}
			System.out.println("消费者已经消费了第"+num+"件货");
			num--;
			
			this.notify();  //唤醒等待的线程
		}
		
	}
}
2.线程池

概念:可以认为是线程对象的容器,预先创建多个线程对象,然后根据这些对象可以实现复用
好处:减少创建和销毁线程的数目,提升性能 
复用机制: 用完了线程对象后,重新回收到线程池中

class Task implements Runnable{
	@Override
	public void run() {
		for(int i=1;i<=10;i++) {
			System.out.println(Thread.currentThread().getName()+"===>"+i);
		}
	};
}

public class Test1 {
	public static void main(String[] args) {
		//创建一个单个线程的线程池对象
		//ExecutorService es = Executors.newSingleThreadExecutor();
		
		//创建一个带缓冲区的线程池对象,灵活控制线程对象,有多少任务,我就创建多少个线程对象
		//ExecutorService es = Executors.newCachedThreadPool();
		
		//创建固定个数的线程池对象,如果任务过多,则用回收线程对象去处理多余任务
		ExecutorService es = Executors.newFixedThreadPool(2);
		Task task = new Task();
		es.submit(task);  //类似,线程.start()
		es.submit(task);
		es.submit(task); //谁先用完并回收,就谁去执行新任务
		
		es.shutdown();  //关闭线程池
	}
}
3.Callable接口与Future接口

Callable接口: 和Runnable类似,也是处理任务的接口
区别: Callable是带返回值的接口,可以将线程中处理完的数据返回

Future接口,该对象接收submit的返回值,可以求出call返回值

//案例: 使用两个线程计算1~50,51~100的和,并进行汇总
public class Test2 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService es = Executors.newFixedThreadPool(2);
		Future future = es.submit(new Callable() {
			@Override
			public Integer call() throws Exception {
				int sum = 0;
				for(int i=1;i<=50;i++) {
					sum += i;
				}
				return sum;
			}
		});
		
		Future future2 = es.submit(new Callable() {

			@Override
			public Integer call() throws Exception {
				int sum = 0;
				for(int i=51;i<=100;i++) {
					sum += i;
				}
				return sum;
			}
		});
		
		//get方法类似线程基础的join,在主线程中阻塞
		int sum = future.get()+future2.get();
		System.out.println("两个线程的和:"+sum);
		
	}
}
4.重入锁与读写锁 4.1重入锁

重入锁:Lock接口    实现类:ReentrantLock
与synchronized类似,用于加锁的
提供了两个方法: lock()-获取锁   unlock()-释放锁

class MyList{
	String[] ss = {"A","B","",""};
	int   index = 2;
	Lock lock = new ReentrantLock();
	
	public void add(String value) {
		//有多个线程可以调用add方法
		lock.lock();  //加锁
		try {
			ss[index] = value;
			index++;
		} finally {
			lock.unlock();
		}
	}
}

public class Test1 {
	public static void main(String[] args) throws InterruptedException {
		MyList list = new MyList();
		Thread th1 = new Thread(new Runnable() {
			@Override
			public void run() {
				list.add("hello");
			}
		});
		th1.start();
		
		Thread th2 = new Thread(new Runnable() {
			@Override
			public void run() {
				list.add("world");
			}
		});
		th2.start();
		th1.join();   th2.join();
		
		System.out.println(Arrays.toString(list.ss));
	}
}
4.2读写锁

读写锁:一般用在读远远高于写的情况,可以提升线程执行的性能
读写锁,在读与读之间是不互斥,不阻塞的,所以性能会提升

class MyClass{
	//加入读写锁
	ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	ReadLock rl = readWriteLock.readLock();
	WriteLock wl = readWriteLock.writeLock();
	
	Integer value;
	public Integer getValue() {
		try {
			rl.lock();
			return value;
		} finally {
			rl.unlock();
		}
	}
	
	public void setValue(Integer value) {
		try {
			wl.lock();
			this.value = value;
		} finally {
			wl.unlock();
		}
		
	}
}

public class Test2 {
	public static void main(String[] args) {
		MyClass myClass = new MyClass();
		Runnable rt = new Runnable() {
			@Override
			public void run() {
				myClass.getValue();
			}
		};
		
		Runnable wt = new Runnable() {
			@Override
			public void run() {
				myClass.setValue(1);
			}
		};
		
		ExecutorService es = Executors.newFixedThreadPool(20);
		
		long start = System.currentTimeMillis();
		for(int i=0;i<18;i++) {
			es.submit(rt);  //18个线程用于读操作
		}
		for(int i=0;i<2;i++) {
			es.submit(wt);  //2个线程用于写操作
		}
		es.shutdown();
		while(!es.isTerminated()){}  //阻塞,确保所有线程结束后,才往下走
		
		System.out.println(System.currentTimeMillis()-start);
		
	}
}
5.线程安全的集合 5.1Collections提供的安全集合
//Collections工具类中提供了针对List,Set,Map的安全集合
//其安全机制性能方面有比较大的影响,一般使用并发安全集合

public class Test1 {
	public static void main(String[] args) {
		List list = Collections.synchronizedList(new ArrayList());
		
		//多个线程进入add方法
		list.add(2);
	}
}
5.2CopyonWriteArrayList

CopyOnWriteArrayList: ArrayList的安全集合(读写并发)
内部进行了加锁,且性能方面比Collestions提供的安全集合更高
该安全集合具有读写分离的特性
读无锁,写有锁,读写之间不互斥,不阻塞,在内部拷贝了一份副本存数据
往往也是用在读多写上的情况

public class Test2 {
	public static void main(String[] args) {
		List list = new CopyOnWriteArrayList();
		
		for(int i=0;i<5;i++) {
			final int temp = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					
					//T1 T2 T3
					//读写并发执行---执行效率很高
					list.add(Thread.currentThread().getName()+"-->"+temp);
					
					System.out.println(list);  //读
				}
			}).start();
		}
	}
}
5.3CopyonWriteArraySet

CopyOnWriteArraySet: 安全的set集合,底层实现通过CopyOnWriteArrayList
该类也是读写分离的set集合类,该类具备存储唯一性

public class Test3 {
	public static void main(String[] args) {
		Set set = new CopyOnWriteArraySet();
		set.add("苹果");
		set.add("香蕉");
		set.add("苹果");
		System.out.println(set);
	}
}
5.4 线程安全的HashMap

ConcurrentHashMap: 并发的HashMap(前提是安全)
Coolections中也提供了线程安全的Map,只不过锁的是整个hash表

public class Test1 {
	public static void main(String[] args) {
		Map map = new ConcurrentHashMap();
		for(int i=0;i<16;i++) {
			final int temp = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					map.put(Thread.currentThread().getName(), "value:"+temp);
					System.out.println(map);
				}
			}).start();
		}
	}
}

 6.队列 6.1Queue队列接口

Queue:队列的接口,特点:先进先出
linkedList实现类就实现了该接口

public class Test1 {
	public static void main(String[] args) {
		Queue queue = new linkedList();
		
		
		
		//如果队列没有元素,则返回null--推荐
		queue.offer(1);
		queue.offer(3);
		queue.offer(2);
		
		System.out.println(queue.peek());  //取元素不移除
		System.out.println(queue.poll());  //取元素并移除
		System.out.println(queue);
	}
}
6.2ConcurrentlinkedQueue实现类

ConcurrentlinkedQueue: 在多线程中,性能最高的并发的队列
内部采用了CAS无锁交换算法进行存储
有3个参数:  V(要改变的变量)      E(预期值)      N(新值)
执行过程中,如果V=E,那么N就可以改变V变量的值了

public class Test2 {
	public static void main(String[] args) throws InterruptedException {
		Queue queue = new ConcurrentlinkedQueue();
		
		Thread th1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for(int i=1;i<=5;i++) {
					queue.offer(i);
				}
			}
		});
		th1.start();
		
		Thread th2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for(int i=6;i<=10;i++) {
					queue.offer(i);
				}
				
			}
		});
		th2.start();
		
		th1.join();  th2.join();
		

		
		for(int i=1;i<=10;i++) {
			System.out.println(queue.poll());
		}
		
		
	}
}
6.3阻塞队列

BlockingQueue:阻塞队列的接口
实现类有: 有界队列ArrayBlockingQueue(推荐),无界队列linkedBlockingQueue
有界队列是有长度限制    无界队列可以认为没有
有两个阻塞方法: put,take ,该阻塞方法的使用类似于生产者消费者用法
put:一般不能超过有界队列长度,超过了阻塞       take,没有值时阻塞

public class Test3 {
	public static void main(String[] args) throws InterruptedException {
		BlockingQueue queue = new ArrayBlockingQueue(3);
		queue.put("苹果");
		queue.put("香蕉");
		queue.put("橘子");
		System.out.println(queue.take()); //取出并移除
		queue.put("西瓜"); //限制存3个,第4个阻塞了
		System.out.println(queue.take()); //取出并移除
		System.out.println(queue);
	}
}
6.4有界队列应用
//通过阻塞队列模拟生产者消费者模型
//案例:生产者和消费者个打印1~100,每次最多生产或消费4个
public class Test4 {
	public static void main(String[] args) {
		BlockingQueue queue = new ArrayBlockingQueue(4);
		
		//负责生产的线程
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for(int i=1;i<=100;i++) {
					try {
						queue.put(i);
						System.out.println("已经生产了第"+i+"件货");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
		}).start();
		
		
new Thread(new Runnable() {
			
			@Override
			public void run() {
				for(int i=1;i<=100;i++) {
					try {
						System.out.println("已经消费了第"+i+"件货");
						queue.take();
						
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
		}).start();
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/605555.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号