//======================代码案例==========================
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. 多线程高级
//2.1 线程池(重点)
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(); //关闭线程池
}
}
//2.2 Callable接口
//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);
}
}
//2.3 重入锁
//重入锁: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));
}
}
//2.4 读写锁
//读写锁:一般用在读远远高于写的情况,可以提升线程执行的性能
//读写锁,在读与读之间是不互斥,不阻塞的,所以性能会提升
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);
}
}
//3.线程安全的集合
//3.1 Collections提供的安全集合
//Collections工具类中提供了针对List,Set,Map的安全集合
//当然他们的安全机制性能方面有比较大的影响,一般我们会用后续并发安全集合
public class Test1 {
public static void main(String[] args) {
List list = Collections.synchronizedList(new ArrayList());
//多个线程进入add方法
list.add(2);
}
}
//3.2 CopyonWriteArrayList
//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();
}
}
}
//3.3 CopyonWriteArraySet
//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);
}
}