java线程开发
-
生产者、消费者
wait() notifyall()
商店: 货架–数组
面包商:有多个 多线程 要往数组里方面包
顾客: 买面包,只要买走了,唤醒面包商
-
线程池
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(); } }
-
使用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(); } } }
-
线程安全集合
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();
}
System.out.println("写入:"+this.value);
this.value = 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));
}
}
非线程安全的集合如何变为线程安全?
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>();
}
}
队列:
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、队列