day19--线程池,异步,Lock锁(读写),线程安全的集合,队列

java线程开发

一、内容回顾

1、线程的实现方式

2、线程的5种状态,及状态的转换

3、线程安全问题:多个线程操作同一资源

4、synchronized

5、死锁

二、今日内容

1、生产者、消费者设计模式

​ wait() notifyall()

2、线程池

3、Callable方式实现线程

4、线程安全的集合

1、生产者、消费者设计模式

商店:货架—数组5

面包商:有多个 多线程 要往数组里放面包

顾客:买面包,买光后,唤醒面包商

2、线程池

package com.qf.pro2103.day19;

import java.lang.reflect.Executable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//创建固定数量的线程池
		ExecutorService es=Executors.newFixedThreadPool(4);
		//创建动态数量的线程池
		//ExecutorService es2=Executors.newCachedThreadPool();
		//线程池里只有一个线程
		//ExecutorService es=Executors.newSingleThreadExecutor();
		//创建任务
		Runnable runnable=new Runnable(){
			private  int ticket=50;
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
					synchronized (this) {
						if(ticket<=0){
							break;
						}
						System.out.println(Thread.currentThread().getName()+"买了"+ticket+"张票");
						ticket--;
					}
				}
			}
			
		};
		//到线程池种获取线程来执行售票任务
		for(int i=0; i<5; i++){
			es.submit(runnable);
		}
		//销毁线程池,等待线程池里的所有线程都执行结束后才销毁
		es.shutdown();
	}

}

3、Callable实现线程

package com.qf.pro2103.day19;

import java.util.concurrent.Callable;

public class CallableDemo implements Callable<Integer> {

	@Override
	public Integer call() throws Exception {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+"开始计算");
		int sum=0;
		for(int i=1; i<=100; i++){
			sum+=i;
			Thread.sleep(100);
		}
		return sum;
	}

}

package com.qf.pro2103.day19;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class TestCallableDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CallableDemo callable=new CallableDemo();
		//把Callable接口的实现类,作为任务传递给Future
		FutureTask<Integer> task=new FutureTask<Integer>(callable);
		//再创建线程类
		Thread t1=new Thread(task);
		t1.start();
		
		//接收线程的返回结果
		try {
			//等待call执行完毕后,才返回结果
			int sum=task.get();
			System.out.println("计算结果是:"+sum);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

4、Lock锁

读写锁:

互斥规则:写-写 互斥

​ 读-写 互斥

​ 读-读 不互斥

适用场景:读操作较多,写操作较少时,提升了读的效率

package com.qf.pro2103.day19;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

public class ReadWriteLock {
	//创建读写锁
	private  ReentrantReadWriteLock rrl=new ReentrantReadWriteLock();
	//从读写锁中获取 读 锁
	private ReadLock readLock=rrl.readLock();
	//从读写锁中获取 写  锁
	private WriteLock writeLock=rrl.writeLock();
	
	private Lock lock=new ReentrantLock();
	
	private String value;
	
	//读
	public String getValue() {
		//使用读锁即可    如果多个线程同时读取,不互斥
		//readLock.lock();
		lock.lock();
		try{
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("读取:"+this.value);
			return value;
		}finally{
			//readLock.unlock();
			lock.unlock();
		}
	}
	//写
	public void setValue(String value) {
		//writeLock.lock();
		lock.lock();
		try{
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			this.value = value;
			System.out.println("写入:"+this.value);
		}finally{
			//writeLock.unlock();
			lock.unlock();
		}
	}

}

package com.qf.pro2103.day19;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestReadWrite {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExecutorService es=Executors.newFixedThreadPool(20);
		ReadWriteLock readWriteDemo=new ReadWriteLock();
		
		//任务
		Runnable read=new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				readWriteDemo.getValue();
			}
		};
		Runnable write=new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				readWriteDemo.setValue("张三:"+new Random().nextInt(100));
			}
		};
		//获取开始时间
		long start=System.currentTimeMillis();
		for(int i=0; i<2; i++){
			es.submit(write);
		}
		for(int i=0;i<18;i++){
			es.submit(read);
		}
		es.shutdown();
		while(!es.isTerminated()){
			
		}
		long end=System.currentTimeMillis();
		System.out.println("用时:"+(end-start));
	}

}

5、线程安全的集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UixTlVRF-1629455713522)(…\img\Collection全部集合.png)]

非线程安全的集合如何变为线程安全?

package com.qf.pro2103.day19;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

public class Demo1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ArrayList<String> list=new ArrayList<String>();
		//线程安全的集合---加同步锁
		//效率低:读读之间  读写之间  写写之间  都互斥
		List<String> list2= Collections.synchronizedList(list);
		
		//线程安全
		//读读之间  读写之间 不互斥  只有写写才互斥  效率优于线程安全的ArrayList
		CopyOnWriteArrayList<String> list3=new CopyOnWriteArrayList<>();
		list.add("hello");
		
		HashSet<String> set=new HashSet<String>();
		Set<String> set2=Collections.synchronizedSet(set);
		//读读之间  读写之间 不互斥  只有写写才互斥  效率优于线程安全的HashSet
		Set<String> set3= new CopyOnWriteArraySet<>();
		
		HashMap<String, String> map=new HashMap<String,String>();
		//Map加锁后,等同于HashTable   对整个数组加锁
		Map<String, String> map2= Collections.synchronizedMap(map);
		
		//线程安全的效率高的Map:不是对整个数组加锁,而是对数组元素及链表加锁
		//分段锁,最优情况下ConcurrentHashMap是线程安全的HashMap效率的16倍
		ConcurrentHashMap<String, String> cMap=new ConcurrentHashMap<String,String>();
		
		
	}

}

6、队列

package com.qf.pro2103.day19;

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Demo2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//声明队列
		//参数:队列里允许存放的值的个数
		Queue<String> stuQueue=new ArrayBlockingQueue<String>(3);
		Queue<String> stuQueue2=new LinkedBlockingQueue<String>(3);
		//添加数据
		//add() 如果达到队列的上限,会抛出异常
		//offer() 添加元素,达到上限后,返回false
		stuQueue.add("jiayukun");
		stuQueue.add("dongjiaxin");
		stuQueue.add("zhuhongtao");
		//先进先出
		//poll() 获取队列中的第一个元素,获取后删除
		//peek() 获取第一个元素,但是不删除
		String getStr=stuQueue.poll();
		System.out.println(getStr);
		String getStr2=stuQueue.poll();
		System.out.println(getStr2);
	}

}

总结:

1、阻塞: sleep() join() sync同步锁 wait()

​ 处于wait的线程需要notify()唤醒

【面试题】wait和sleep的区别?

  • 1、所属类不同 sleept是Thread类的 wait是Object
  • 2、sleep()可以用在任何位置(有、无锁都可以) wait()只能用在锁中
  • 3、sleep()在睡眠时,锁依然有效,而wait()会释放锁

2、生产者消费者模式

3、线程池 为什么用? 线程池的创建方式

4、实现Callable接口实现线程

5、Lock

​ 重点: 读写锁

6、线程安全的集合

7、队列

1、阻塞: sleep() join() sync同步锁 wait()

​ 处于wait的线程需要notify()唤醒

【面试题】wait和sleep的区别?

  • 1、所属类不同 sleept是Thread类的 wait是Object
  • 2、sleep()可以用在任何位置(有、无锁都可以) wait()只能用在锁中
  • 3、sleep()在睡眠时,锁依然有效,而wait()会释放锁

2、生产者消费者模式

3、线程池 为什么用? 线程池的创建方式

4、实现Callable接口实现线程

5、Lock

​ 重点: 读写锁

6、线程安全的集合

7、队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值