Java多线程编程(3)

五、线程协调

线程协调:wait和notify方法java

死锁发生时的条件:数组

(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();
            }
        }
    }
}

懒汉式单例模式ide

懒汉式单例模式 在使用这个对象时,才去查看这个对象是否建立。若是没建立就立刻建立;若是已经建立,就返回这个实例。 线程不安全,须要加上同步锁,影响了程序执行效率。 饿汉式单例模式 在加载这个类的时候,就先建立好一个对象实例,等待调用。 天生线程安全,类加载的时候初始化一次对象,效率比懒汉式高。函数

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();
    }
}

生产者消费者例子性能

多线程环境下,咱们常常须要多个线程的并发和协做。这个时候,就须要了解一个重要的多线程并发协做模型“生产者/消费者模式”。this

什么是生产者?       生产者指的是负责生产数据的模块(这里模块多是:方法、对象、线程、进程)。

什么是消费者?       消费者指的是负责处理数据的模块(这里模块多是:方法、对象、线程、进程)。

什么是缓冲区?       消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。

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<Product> productList;
    public ProductPool(int maxSize, List<Product> 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<Product>());
        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<Product> blockingQueue;
    public Producer(BlockingQueue<Product> 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<Product> blockingQueue;
    public Consumer(BlockingQueue<Product> 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<Product> BlockingQueue = new 	ArrayBlockingQueue<Product>(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 {
    // 二、静态内部类
    static class Love2 implements ILove {
        @Override
        public void lambda() {
            System.out.println("I Love Lambda 2");
        }
    }
    public static void main(String[] args) {
        // 一、外部类
        ILove love = new Love();
        love.lambda();
        // 二、静态内部类
        ILove love2 = new Love2();
        love2.lambda();
        // 三、局部内部类
        class Love3 implements ILove {
            @Override
            public void lambda() {
                System.out.println("I Love Lambda 3");
            }
        }
        ILove love3 = new Love3();
        love3.lambda();
        // 四、匿名内部类
        ILove love4 = new ILove() {
            @Override
            public void lambda() {
                System.out.println("I Love Lambda 4");
            }
        };
        love4.lambda();
        // 五、Lambda
        ILove love5 = () -> {
            System.out.println("I Love Lambda 5");
        };
        love5.lambda();
    }
}
// 函数式接口
interface ILove {
    void lambda();
}

// 一、实现类
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<String> list = new ArrayList<String>();
        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<String> list = new ArrayList<String>();
        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<String> list = new CopyOnWriteArrayList<String>();
        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();
        }
    }

}