程序(Process)是一个静态的概念,是指令和数据的有序集合。
进程是一个动态的概念,程序运行就是一个进程。进程是操作系统分配资源的基本单位。
线程(Thread)是CPU调度和执行的单位。
进程和线程是包含与被包含的关系,一个进程可以有多个线程。JAVA中一个进程至少拥有两个线程(main/gc线程)。
1.继承Thread类
缺点:java是单继承,使用继承方式后代码耦合
public class CreatThread1 extends Thread{
@Override
public void run() {
for(int i=0;i<200;i++){
System.out.println("线程"+i);
}
}
public static void main(String[] args) throws InterruptedException {
CreatThread1 thread = new CreatThread1();
thread.start();
for(int i=0;i<1000;i++){
System.out.println("主线程"+i);
}
}
}
2.实现Runnable接口
public class CreateThread2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("线程"+i);
}
}
public static void main(String[] args) {
CreateThread2 thread = new CreateThread2();
new Thread(thread).start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程"+i);
}
}
}
3.实现Callable接口
这种方式是对于Runnable的升级版,Runnable创建的线程没有返回值,而Callable有返回值,而且多了其他操作。
4.基于四种线程池的创建方式
public class TestThreadPoolExecutor {
public static void main(String[] args) {
// ExecutorService threadPool = Executors.newSingleThreadExecutor();//一个线程,不建议使用
// ExecutorService threadPool = Executors.newFixedThreadPool(5);//指定线程个数,不建议使用
// ExecutorService threadPool = Executors.newCachedThreadPool();//根据内存而定线程个数,不建议使用
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,//一般线程池可以有几个
Runtime.getRuntime().availableProcessors(),//最大连接个数,一般是当前电脑的核数
3,//超时时间
TimeUnit.SECONDS,//超时单位
new LinkedBlockingDeque<>(3),//线程池已满,在外面最多可以等待进入线程池的个数
Executors.defaultThreadFactory(),//默认工程,一般设置这个就行,固定
new ThreadPoolExecutor.DiscardPolicy());//指定线程的拒绝策略
try {
for (int i = 0; i < 100; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
不太推荐jdk中的stop方式,stop已经被弃用,如果先前受这些监视器保护的任何对象处于不一致的状态,则损坏的对象将变得对其他线程可见,可能导致任意行为。推荐使用自定义标志位方式来使线程停止。
public class ThreadStop implements Runnable {
//1.设置标志位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run...Thread"+i++);
}
}
//2.设置一个公开的方法停止线程
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
ThreadStop threadStop = new ThreadStop();
new Thread(threadStop).start();
//主线程
for (int i = 0; i < 1000; i++) {
System.out.println("main.."+i);
if (i==900){//当主线程中的i=900时,run线程停止
threadStop.stop();
System.out.println("run线程停止了");
}
}
}
}
1、notify()只能唤醒一个wait()线程,然而notifyAll()可以唤醒多个wait()线程;
2、两个都必须在synchronized中使用,过程不释放锁;
3、当每个线程都有特定锁的时候,只有等待这个锁的线程才能被唤醒,也就是线程2的notify()或notifyAll()不能唤醒线程1的wait();
1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。
2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。
2)禁止进行指令重排序。
3)volatile 不是原子性操作
4)可以使用原子类,如AtomicInteger
start()方法: 它会启动一个新线程,并将其添加到线程池中,待其获得CPU资源时会执行run()方法,start()不能被重复调用。
run()方法:它和普通的方法调用一样,不会启动新线程。只有等到该方法执行完毕,其它线程才能获得CPU资源。
wait()方法强制当前线程释放对象锁。这意味着在调用某对象的wait()方法之前,当前线程必须已经获得该对象的锁。因此,线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方法。.
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
Semaphore 是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。 Semaphore 可以用来构建一些对象池,资源池之类的, 比如数据库连接池实现互斥锁(计数器为 1)我们也可以创建计数为 1 的 Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。
用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。 默认情况下不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当队列可用时,可以按照阻塞的先后顺序访问队列,即先阻塞的生产者线程,可以先往队列里插入元素,先阻塞的消费者线程,可以先从队列里获取元素。通常情况下为了保证公平性会降低吞吐量。我们可以使用以下代码创建一个公平的阻塞队列。
Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而 Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值。可以认为是带有回调的Runnable。
Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。
并发: 多线程操作同一个资源(并发编程—多个线程操作同一个资源类), CPU 只有一核,可以使用CPU快速交替, 模拟出来多条线程
并行:CPU多核,多个线程可以同时执行
使用ArrayList,当多个线程同时写入数据时会产生java.util.ConcurrentModificationException异常(并发修改异常)
解决方案:使用vector代替arrylist,List list = new Vector<>();
使用collections工具类,List list = Collections.synchronizedList(new ArrayList<>());
CopyOnWrite,List list = new CopyOnWriteArrayList<>();
相当于减法器
public class TestCountDownLatch {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"线程已完成");
countDownLatch.countDown();//数量-1
},String.valueOf(i)).start();
}
countDownLatch.await();//等待计数器归零,然后再向下执行
System.out.println("线程全部执行完毕");
}
}
相当于加法器
public class TestCyclicBarrier {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("7个线程都已完成");
});
for (int i = 0; i < 7; i++) {
final int temp=i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"完成第"+temp+"个进程");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
读写锁允许访问共享数据时的并发性高于互斥锁所允许的并发性。 它利用了这样一个事实:一次只有一个线程( 写入线程)可以修改共享数据,在许多情况下,任何数量的线程都可以同时读取数据(因此读取器线程)。
BlockingQueue方法有四种形式,具有不同的操作方式,不能立即满足,但可能在将来的某个时间点满足:一个抛出异常,第二个返回一个特殊值( null或false ,具体取决于操作),第三个程序将无限期地阻止当前线程,直到操作成功为止,而第四个程序块在放弃之前只有给定的最大时限。

池化技术包括:线程池、JDBC的连接池、内存池、对象池等
池化技术:事先准备好一些资源,如果有人要用,就来我这里拿,用完之后再归还,以此来提高效率
线程池的好处:降低资源的消耗;提高响应的速度;方便管理;线程复用、可以控制最大并发数、管理线程;
public class TestThreadPoolExecutor {
public static void main(String[] args) {
// ExecutorService threadPool = Executors.newSingleThreadExecutor();//一个线程,不建议使用
// ExecutorService threadPool = Executors.newFixedThreadPool(5);//指定线程个数,不建议使用
// ExecutorService threadPool = Executors.newCachedThreadPool();//根据内存而定线程个数,不建议使用
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,//一般线程池可以有几个
Runtime.getRuntime().availableProcessors(),//最大连接个数,一般是当前电脑的核数
3,//超时时间
TimeUnit.SECONDS,//超时单位
new LinkedBlockingDeque<>(3),//线程池已满,在外面最多可以等待进入线程池的个数
Executors.defaultThreadFactory(),//默认工程,一般设置这个就行,固定
new ThreadPoolExecutor.DiscardPolicy());//指定线程的拒绝策略
try {
for (int i = 0; i < 100; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
函数式接口、断定型接口、消费型接口、供给型接口
public class TestStream {
public static void main(String[] args) {
User1 u1 = new User1(1, "a", 21);
User1 u2 = new User1(2, "b", 22);
User1 u3 = new User1(3, "c", 23);
User1 u4 = new User1(4, "d", 24);
User1 u5 = new User1(5, "e", 25);
List<User1> list = Arrays.asList(u1, u2, u3, u4, u5);
list.stream().filter(u->{return u.getId()%2==0;})
.map(u->{return u.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
//计算0-1000000000的和
System.out.println(LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0,Long::sum));
}
}
ForkJoin 工作特点:工作窃取!
原理是双端队列!从上面和下面都可以去进行执行!,当B线程完成后,B线程回去执行A线程未完成的任务,提高效率。
即Future,设计的初衷: 对将来的某个事件的结果进行建模,类似ajax
1.没有返回值的runAsync异步回调
public class FutureTest1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " runAsync--->void");
});
System.out.println("111111");
System.out.println(voidCompletableFuture.get()); // 获取异步执行结果
}
}
2.有返回值的异步回调supplyAsync
public class supplyAsyncTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "supplyAsync=>Integer");
int i = 10 / 0;
return 1024;
});
//设置integerCompletableFuture的回调
System.out.println(integerCompletableFuture.whenComplete((t, u) -> {
System.out.println("t=>" + t);// 成功结果
System.out.println("u=>" + u);// 错误信息:
}).exceptionally((e) -> {
System.out.println(e.getMessage());
return 233;
}).get()); //获取回调成功或者失败的返回结果
}
}