进程是计算机的程序关于某数据集合的一次运行活动
进程是资源分配的最小单位,线程是资源调度的最小单位
线程是进程中一个独立的执行流
**进程和程序:**程序是指令、数据及其组织形式的描述,进程是程序的实体
线程状态图:
五个状态:
并发与并行:
同步与异步:
异步与多线程:
什么是多线程:
继承Thread类:
实现Runnable接口:
Callable接口和FutureTask
线程池
public class ThreadTest {
public static void main(String[] args) {
//方式1 Thread
MyThread myThread = new MyThread("w");
myThread.start();
//方式2 Runnable
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable,"我的线程2").start();
//方式3 Callable和FutureTask
MyCallable myCallable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
new Thread(futureTask,"我的线程3").start();
//方式4 线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 2L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
threadPool.execute(myRunnable);
}
}
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("我的线程");
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("创建可执行任务");
}
}
class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
System.out.println("创建MyCallable");
return 1;
}
}
Java线程优先级是整数,范围(Thread.MIN_PRIORITY )1 —(Thread.MAX_PRIORITY )10,默认优先级 NORM_PRIORITY(5)。
更改优先级:
setPriority(int newPriority)
关键字:
方法:
问题:
volatile原理:
将变量的修改直接写入主存中,保证各个线程对于变量的可见性。
sleep方法和wait方法:
为什么wait方法是Object类
运行完停止
自定义中断标志符
使用volatile修饰一个变量作为标识
volatile boolean flag = false;
Thread t = new Thread(()->{
while (true) {
System.out.println("hello");
if (flag) {
System.out.println("线程结束");
break;
}
}
});
t.start();
Thread.sleep(1000);
flag = true;
interrupt:
使用interrupt和isInterrupted使线程停止。
Thread t = new Thread(()->{
while (!Thread.currentThread().isInterrupted()) {
System.out.println("hello");
}
});
t.start();
Thread.sleep(1000);
t.interrupt();
public class ConsumerProducer {
public static void main(String[] args) {
Buffer buffer = new Buffer(5);
Producer producer = new Producer(buffer);
Consumer consumer = new Consumer(buffer);
new Thread(producer).start();
new Thread(consumer).start();
}
}
//资源类
class Buffer {
private Queue<Integer> queue;
private int size;
public Buffer(int size) {
this.queue = new LinkedList<Integer>();
this.size = size;
}
public synchronized void add(int i) throws InterruptedException {
//判断
while (queue.size() >= size) {
wait();
}
//干活
queue.add(i);
System.out.println("生产者生成了:"+i);
//通知
notifyAll();
}
public synchronized int get() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
Integer value = queue.poll();
notifyAll();
return value;
}
}
class Producer implements Runnable {
private Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
buffer.add(i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
int thing = buffer.get();
System.out.println("消费者消费了:"+thing);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Lock和synchronize的比较:
synchronized卖票例子:
class Ticket {
private int ticketNum = 30;
public synchronized void sale() {
if( ticketNum > 0) {
System.out.println(Thread.currentThread().getName()+"卖出第"+(ticketNum--)+"票,还剩"+ticketNum+"张票");
}
}
}
public class SaleTicketSyn {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0; i< 30; i++)
ticket.sale();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0; i< 30; i++)
ticket.sale();
}
},"B").start();
}
}
可重入锁卖票:
class TicketL {
private int ticketNum = 30;
private final ReentrantLock lock = new ReentrantLock();
public synchronized void sale() {
lock.lock();
try {
if( ticketNum > 0) {
System.out.println(Thread.currentThread().getName()+"卖出第"+(ticketNum--)+"票,还剩"+ticketNum+"张票");
}
} finally {
lock.unlock();
}
}
}
虚假唤醒问题:
出现虚假唤醒的例子:
class Share {
private int num = 0;
public synchronized void incr() throws InterruptedException {
if (num != 0) { //使用if
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+":"+num);
this.notifyAll();
}
public synchronized void decr() throws InterruptedException {
if (num == 0) {
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+":"+num);
this.notifyAll();
}
}
public class AddMinusSyn {
public static void main(String[] args) {
Share share = new Share();
new Thread(()->{
for (int i=0; i<20; i++) {
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i=0; i<20; i++) {
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
防止虚假唤醒的例子:
class ShareL {
private int num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void incr() throws InterruptedException {
lock.lock();
try {
while (num != 0) { //使用while
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName()+":"+num);
condition.signalAll();
} finally {
lock.unlock();
}
}
public void decr() throws InterruptedException {
lock.lock();
try {
while (num != 1) {
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+":"+num);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
Object的wait和notify对比Condition的await和signal:
**思路:**使用标志位来控制线程执行顺序
例子:A,B,C轮替执行
class Share {
private int flag = 1;
private ReentrantLock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void funA() throws InterruptedException {
lock.lock();
try {
while (flag != 1) {
c1.await();
}
this.flag = 2;
System.out.println(Thread.currentThread().getName()+"funA");
c2.signal();
} finally {
lock.unlock();
}
}
public void funB() throws InterruptedException {
lock.lock();
try {
while (flag != 2) {
c2.await();
}
this.flag = 3;
System.out.println(Thread.currentThread().getName()+"funB");
c3.signal();
} finally {
lock.unlock();
}
}
public void funC() throws InterruptedException {
lock.lock();
try {
while (flag != 3) {
c3.await();
}
this.flag = 1;
System.out.println(Thread.currentThread().getName()+"funC");
c1.signal();
} finally {
lock.unlock();
}
}
}
异常:并发修改异常
解决方案:
Vector:效率低,比较老
Collections:
CopyOnWriteArrayList:写时复制
解决方案:
解决方案:
两个及以上进程在执行过程中,由于竞争资源或彼此通信而造成的一种阻塞现象,若无外力作用,它们将永远等待下去。
产生死锁的四个原因
判断死锁
例子:
public class LockTest {
Lock lock = new Lock();
public void methodA() {
lock.lock();
try {
System.out.println("A方法已上锁");
this.methodB();
} finally {
lock.unlock();
}
}
public void methodB() {
lock.lock();
try {
System.out.println("B方法已上锁");
} finally {
lock.unlock();
}
}
}
读写锁:一个资源可以被多个读线程访问,或者一个写线程访问,但不能同时存在读写线程,读写互斥,读读共享。
实现方法:
使用Callable接口可以时线程有返回值。
Runnable接口和Callable接口:
FutureTask:
原理:
基于委托的适配器模式
案例:
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//方式1
FutureTask<Integer> futureTask = new FutureTask<>(new CallableClass());
//方式2lambda表达式
FutureTask futureTask1 = new FutureTask(()->{
System.out.println(Thread.currentThread().getName()+"进入callable");
return 200;
});
new Thread(futureTask,"A").start();
System.out.println(futureTask.get());
}
}
class CallableClass implements Callable {
@Override
public Object call() {
System.out.println(Thread.currentThread().getName()+"进入callable");
return 200;
}
}
CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减一的操作,使用await方法等待计数器不大于0,然后继续执行await方法之后的语句。
使用流程:
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i=0; i<6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"走了");
countDownLatch.countDown();
},i+"").start();
}
countDownLatch.await();
System.out.println("线程都运行完了");
CyclicBarrier构造方法第一个参数时目标障碍数,每执行一次障碍数加一,达到目标障碍数之后才会执行await之后的语句。可以理解为加一操作。
使用流程:
final int NUM = 7;
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM,()->{
System.out.println("阻塞七个,我可以运行了");
});
for (int i = 0; i < 7; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"阻塞");
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
},i+"").start();
}
CyclicBarrier和CountDownLatch的区别:
六辆车停3个停车位,加减的操作。
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 6; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"进行停车");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName()+"-----离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
ArrayBlockingQueue
由数组结构组成的有界阻塞队列
LinkedBlockingQueue
由链表组成的有界阻塞队列
DelayQueue
使用优先级队列实现的延迟无界阻塞队列
PriorityBlockingQueue
支持优先级排序的无界阻塞队列
SynchronousQueue
单个元素的队列
LinkedTransferQueue
链表组成的无界阻塞队列
LinkedBlockingDeque
链表组成的双向队列
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过度调度。
Java中的线程池时通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类
特征:
使用演示:
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService threadPool1 = Executors.newFixedThreadPool(5);
ExecutorService threadPool2 = Executors.newSingleThreadExecutor();
ExecutorService threadPool3 = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 10; i++) {
threadPool1.execute(()->{
System.out.println(Thread.currentThread().getName() + "办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool1.shutdown();
}
}
}
实际使用中一般都是自定义线程池:
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 2L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
Fork/Join可以将一个大的任务拆分成许多小任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
计算a加到b的值,每10个进行计算
class MyTask extends RecursiveTask<Integer> {
private static final Integer VALUE = 10;
private int begin;
private int end;
private int result;
public MyTask(int begin,int end) {
this.begin = begin;
this.end = end;
}
@Override
protected Integer compute() {
if((end - begin) <= VALUE) {
for (int i = begin; i <= end; i++) {
result = result + i;
}
} else {
int middle = (begin + end)/2;
MyTask myTask1 = new MyTask(begin,middle);
MyTask myTask2 = new MyTask(middle + 1,end);
myTask1.fork();
myTask2.fork();
result = myTask1.join() + myTask2.join();
}
return result;
}
}
public class ForkJoinTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyTask myTask = new MyTask(0,100);
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);
Integer res = forkJoinTask.get();
System.out.println(res);
forkJoinPool.shutdown();
}
}
CompletableFuture异步回调的使用
public class Asyn {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//没有返回值
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
System.out.println("hi");
});
completableFuture.get();
//有返回值
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(()->{
System.out.println("hi");
return 43;
});
Integer integer = completableFuture1.whenComplete((t, u) -> {
System.out.println(t + " 返回值");
System.out.println(u + " 异常");
}).get();
System.out.println("返回值"+integer);
}
}