线程协调:wait和notify方法
死锁发生时的条件:
(1)互斥条件:一个资源每次只能被一个进程使用。
(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不剥夺条件: 进程已获得的资源,在未使用完之前,不能强行剥夺。
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
public class ThreadCoordinate {
public static void main(String[] args) {
CoordinateA coordinateA = new CoordinateA();
Thread threadA = new Thread(coordinateA, "线程1");
CoordinateB coordinateB = new CoordinateB();
Thread threadB = new Thread(coordinateB, "线程2");
threadA.start();
threadB.start();
}
}
class CoordinateA implements Runnable {
@Override
public void run() {
synchronized ("A") {
System.out.println(Thread.currentThread().getName()
+ "持有了A锁,等待B锁。。。");
try {
"A".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized ("B") {
System.out.println(Thread.currentThread().getName()
+ "持有了A锁和B锁");
}
}
}
}
class CoordinateB implements Runnable {
@Override
public void run() {
synchronized ("B") {
System.out.println(Thread.currentThread().getName()
+ "持有了B锁,等待A锁。。。");
synchronized ("A") {
System.out.println(Thread.currentThread().getName()
+ "持有了B锁和A锁");
"A".notify();
}
}
}
}
懒汉式单例模式
懒汉式单例模式 在使用这个对象时,才去查看这个对象是否创建。如果没创建就马上创建;如果已经创建,就返回这个实例。 线程不安全,需要加上同步锁,影响了程序执行效率。 饿汉式单例模式 在加载这个类的时候,就先创建好一个对象实例,等待调用。 天生线程安全,类加载的时候初始化一次对象,效率比懒汉式高。
public class ThreadSingleton {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
HelloRunnable helloRunnable = new HelloRunnable();
Thread thread = new Thread(helloRunnable);
thread.start();
}
}
}
class Lazybones {
public Lazybones() {
System.out.println("对象实例化了");
}
private static Lazybones lazybones = null;
public static Lazybones getLazybones() {
synchronized ("") {
if (lazybones == null) {
lazybones = new Lazybones();
}
}
return lazybones;
}
}
class HelloRunnable implements Runnable {
@Override
public void run() {
Lazybones.getLazybones();
}
}
生产者消费者例子
多线程环境下,我们经常需要多个线程的并发和协作。这个时候,就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”。
什么是生产者? 生产者指的是负责生产数据的模块(这里模块可能是:方法、对象、线程、进程)。
什么是消费者? 消费者指的是负责处理数据的模块(这里模块可能是:方法、对象、线程、进程)。
什么是缓冲区? 消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。
public class Product {
public String name;
public Product(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class ProductPool {
public int maxSize = 0;
public List productList;
public ProductPool(int maxSize, List productList) {
this.maxSize = maxSize;
this.productList = productList;
}
public synchronized void push(Product product) {
if (this.productList.size() >= this.maxSize) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.productList.add(product);
this.notifyAll();
}
public synchronized Product pop() {
if (this.productList.size() <= 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = this.productList.remove(0);
this.notifyAll();
return product;
}
}
public class Producer implements Runnable {
private ProductPool productPool;
public Producer(ProductPool productPool) {
this.productPool = productPool;
}
@Override
public void run() {
int i = 0;
while (true) {
String name = i++ + "产品";
Product product = new Product(name);
this.productPool.push(product);
System.out.println("生产了" + name);
}
}
}
public class Consumer implements Runnable {
public ProductPool productPool;
public Consumer(ProductPool productPool) {
this.productPool = productPool;
}
@Override
public void run() {
while (true) {
Product product = this.productPool.pop();
System.out.println("消费了" + product.getName() + "产品");
}
}
}
public class MainMethod {
public static void main(String[] args) {
ProductPool productPool =
new ProductPool(10, new LinkedList());
Producer producer = new Producer(productPool);
Thread thread1 = new Thread(producer);
thread1.start();
Consumer consumer = new Consumer(productPool);
Thread thread2 = new Thread(consumer);
thread2.start();
}
}
线程定义:实现Callable接口
前面两种线程定义方式都有这两个问题:
无法获取子线程的返回值;
run方法不可以抛出异常。
为了解决这两个问题,我们就需要用到Callable这个接口了。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class HelloCallable implements Callable {
int i = 0;
@Override
public Object call() throws Exception {
for (int i1 = 0; i1 < 10; i1++) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
}
return i;
}
public static void main(String[] args) {
HelloCallable helloCallable = new HelloCallable();
for (int i = 0; i < 10; i++) {
FutureTask futureTask = new FutureTask(helloCallable);
Thread thread = new Thread(futureTask, "子线程" + i);
thread.start();
try {
System.out.println("子线程" + i + "返回值:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
线程同步:锁对象
同步代码依赖于一种简单的可重入锁。这种锁易于使用,但有很多限制。java.util.concurrent.locks软件包支持更复杂的锁定习惯用法 。 Lock对象的工作方式非常类似于同步代码所使用的隐式锁。与隐式锁一样,一次只能有一个线程拥有一个Lock对象。Lock对象还wait/notify通过其关联的Condition对象支持一种机制 。
import java.util.concurrent.locks.ReentrantLock;
public class ThreadLock implements Runnable {
public static int ticket = 100;
ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
while (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
reentrantLock.lock();
if (ticket <= 0) {
return;
}
System.out.println(Thread.currentThread().getName() + "卖了1张票,剩余" + --ticket + "张票");
reentrantLock.unlock();
}
}
public static void main(String[] args) {
ThreadLock threadLock = new ThreadLock();
Thread thread1 = new Thread(threadLock, "售票员1");
thread1.start();
Thread thread2 = new Thread(threadLock, "售票员2");
thread2.start();
Thread thread3 = new Thread(threadLock, "售票员3");
thread3.start();
}
}
线程池
Java中创建和销毁一个线程是比较昂贵的操作,需要系统调用。频繁创建和销毁线程会影响系统性能。 使用线程池带来以下好处: 降低资源的消耗。线程本身是一种资源,创建和销毁线程会有CPU开销;创建的线程也会占用一定的内存。 提高任务执行的响应速度。任务执行时,可以不必等到线程创建完之后再执行。 提高线程的可管理性。线程不能无限制地创建,需要进行统一的分配、调优和监控。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new ThreadPool());
executorService.execute(new ThreadPool());
executorService.execute(new ThreadPool());
executorService.shutdown();
}
}
并发集合: BlockingQueue
BlockingQueue实现被设计为主要用于生产者-消费者队列,如果BlockingQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间时才会被唤醒。 BlockingQueue实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来原子地实现其效果。
public class Product {
private String name;
public Product(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
BlockingQueue blockingQueue;
public Producer(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
int i = 0;
while (true) {
try {
Product product = new Product("" + i++);
blockingQueue.put(product);
System.out.println("生产产品:" + product.getName());
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable {
BlockingQueue blockingQueue;
public Consumer(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
while (true) {
Product product = blockingQueue.take();
System.out.println("消费产品: " + product.getName());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
import java.util.concurrent.*;
public class MainMethod {
public static void main(String[] args) {
BlockingQueue BlockingQueue = new ArrayBlockingQueue(100);
Producer producer = new Producer(BlockingQueue);
Consumer consumer = new Consumer(BlockingQueue);
new Thread(producer).start();
new Thread(consumer).start();
}
}
静态代理
静态代理就是在编译时就确定了代理类与被代理类的关系。
public class StaticProxy {
public static void main(String[] args) {
Me me = new Me();
WeddingCompany weddingCompany = new WeddingCompany(me);
weddingCompany.marryMethod();
}
}
interface Marry {
void marryMethod();
}
class Me implements Marry {
@Override
public void marryMethod() {
System.out.println("哈哈,我要结婚了!!!");
}
}
class WeddingCompany implements Marry {
private Marry marrry;
public WeddingCompany(Marry marrry) {
this.marrry = marrry;
}
@Override
public void marryMethod() {
before();
this.marrry.marryMethod();
after();
}
public void before() {
System.out.println("结婚之前,布置现场。");
}
public void after() {
System.out.println("结婚之后,收取费用。");
}
}
Lamda表达式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。 Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。 使用 Lambda 表达式可以使代码变的更加简洁紧凑。
public class LambdaExpression {
// 2、静态内部类
static class Love2 implements ILove {
@Override
public void lambda() {
System.out.println("I Love Lambda 2");
}
}
public static void main(String[] args) {
// 1、外部类
ILove love = new Love();
love.lambda();
// 2、静态内部类
ILove love2 = new Love2();
love2.lambda();
// 3、局部内部类
class Love3 implements ILove {
@Override
public void lambda() {
System.out.println("I Love Lambda 3");
}
}
ILove love3 = new Love3();
love3.lambda();
// 4、匿名内部类
ILove love4 = new ILove() {
@Override
public void lambda() {
System.out.println("I Love Lambda 4");
}
};
love4.lambda();
// 5、Lambda
ILove love5 = () -> {
System.out.println("I Love Lambda 5");
};
love5.lambda();
}
}
// 函数式接口
interface ILove {
void lambda();
}
// 1、实现类
class Love implements ILove {
@Override
public void lambda() {
System.out.println("I Love Lambda 1");
}
}
ArrayList
ArrayList不是线程安全的,他的add方法没有synchronized同步锁控制。
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
System.out.println(list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest2 {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
synchronized ("") {
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(1000);
System.out.println(list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CopyOnWriteArray
CopyOnWriteArrayList是ArrayList 的一个线程安全的变体,其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的。
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListTest {
public static void main(String[] args) {
CopyOnWriteArrayList list = new CopyOnWriteArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
System.out.println(list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}