JUC并发编程学习笔记

JUC并发编程学习笔记

狂神JUC并发编程

总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多。

线程与进程

进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等。一个进程往往包含多个线程,且至少包含一个线程。

线程:进程中的实际运作单位。

Java默认有几个线程?

2个,main和GC

Java创建线程的方式?

3种,继承Thread,实现Runnable,实现Callable.

Java真的可以开启线程么?

Java不能自己开启线程,而是通过调用本地方法,调用C++代码开启线程,Java不能直接操作硬件。

并发与并行

并发:多个线程操作同一个资源。模拟多条线程交替执行,并发编程的本质是充分利用CPU资源,多个线程争抢CPU执行时间片段。

并行:CPU多核,多个线程同时执行。

public static void main(String[] args) { //8 可用的计算资源 System.out.println(Runtime.getRuntime().availableProcessors()); }

注意:Runtime.getRuntime().availableProcessors()返回的是可用的计算资源,而不是CPU物理核心数,对于支持超线程的CPU来说,单个物理处理器相当于拥有两个逻辑处理器,能够同时执行两个线程。


Callable

有返回值

可以跑出异常

重写call()方法

细节

同一个Callable被两条线程执行,会只执行一次,结果会被缓存。

get()方法会阻塞等待线程执行完返回值才继续往下走,一般把获取结果放在最后一行或者用异步通信获取结果。

代码示例 public class CallableTest { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<>(() -> { // TimeUnit.SECONDS.sleep(3); System.out.println("execute call"); return "hello callable"; }); //FutureTask为适配器模式 new Thread(futureTask).start(); //callable只执行一次,结果会被缓存 new Thread(futureTask).start(); //阻塞等待线程执行完返回值才继续往下走,一般把获取结果放在最后一行或者用异步通信获取结果 System.out.println(futureTask.get()); } /**输出: * execute call * hello callable */ } Java线程状态

Java线程一共有6种状态。

public enum State { //新建 NEW, //运行中 RUNNABLE, //阻塞 BLOCKED, //等待 WAITING, //超时等待 TIMED_WAITING, //结束 TERMINATED; }

wait()和sleep()方法的区别?

来着不同的类,wait()属于Object类,而sleep()属于Thread类。

wait()会释放锁,而sleep()不会释放锁。

使用范围不同,wait()在同步代码块中使用,而sleep()可以在任何地方使用。

Lock锁 synchronized锁

synchronized本质是队列加锁。

注意线程是个单独的资源类,使用不用有任何附属的操作。

synchronized代码示例 public class TicketTest { public static void main(String[] args) { Ticket ticket = new Ticket(20); new Thread(() -> { for (int i = 0; i < 20; i++) { ticket.sale(); } }, "Mike").start(); new Thread(() -> { for (int i = 0; i < 20; i++) { ticket.sale(); } }, "Tom").start(); new Thread(() -> { for (int i = 0; i < 20; i++) { ticket.sale(); } }, "Jane").start(); } } @Data @AllArgsConstructor class Ticket { private Integer number; public synchronized void sale() { if (number <= 0) { return; } System.out.println(Thread.currentThread().getName() + "买到了第" + (number--) + "张票,剩余票数" + number); } } /** * 输出:要有顺序的输出才行 * Mike买到了第20张票,剩余票数19 * Mike买到了第19张票,剩余票数18 * Mike买到了第18张票,剩余票数17 * Mike买到了第17张票,剩余票数16 * Mike买到了第16张票,剩余票数15 * Tom买到了第15张票,剩余票数14 * Tom买到了第14张票,剩余票数13 * Tom买到了第13张票,剩余票数12 * Tom买到了第12张票,剩余票数11 * Tom买到了第11张票,剩余票数10 * Tom买到了第10张票,剩余票数9 * Tom买到了第9张票,剩余票数8 * Tom买到了第8张票,剩余票数7 * Tom买到了第7张票,剩余票数6 * Tom买到了第6张票,剩余票数5 * Tom买到了第5张票,剩余票数4 * Tom买到了第4张票,剩余票数3 * Tom买到了第3张票,剩余票数2 * Tom买到了第2张票,剩余票数1 * Tom买到了第1张票,剩余票数0 */ Lock锁示例 public class TicketTest2 { public static void main(String[] args) { Ticket2 ticket = new Ticket2(20,new ReentrantLock()); new Thread(() -> { for (int i = 0; i < 20; i++) { ticket.sale(); } }, "Mike").start(); new Thread(() -> { for (int i = 0; i < 20; i++) { ticket.sale(); } }, "Tom").start(); new Thread(() -> { for (int i = 0; i < 20; i++) { ticket.sale(); } }, "Jane").start(); } } /** * Lock使用三部曲 * 1、创建 ReentrantLock * 2、加锁 lock.lock(); * 3、finally块中释放锁 lock.unlock(); */ @Data @AllArgsConstructor class Ticket2 { private Integer number; private Lock lock; public void sale() { lock.lock(); try { if (number <= 0) { return; } System.out.println(Thread.currentThread().getName() + "买到了第" + (number--) + "张票,剩余票数" + number); } finally { lock.unlock(); } } }

synchronized与Lock的区别?

synchronized是java内置关键字,Lock是一个Java类。

synchronized无法判断获取锁的状态,Lock可以判断是否取到了锁。

synchronized自动加锁释放锁,而Lock需手动加锁释放锁,否则会造成死锁。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxsxy.html