并发编程笔记

单核CPU下,多线程不能实际提高程序运行效率,值是为了能够在不同的任务之间切换。
多核CPU可以并行跑多个线程,可以提高程序运行效率。

java中创建线程的方式
Thread类的方式
Thread t=new Thread(){
  public void run(){
  //要执行的任务
  }
};
t.start();
Runnable 的方式
 Runnable r= () -> System.out.println("进入线程Runnable");

Thread是吧线程和任务合并在一起
Runnable 是吧线程和任务分开了。
用Runnable 让任务类脱离了Thread继承体系,更加灵活。

FutureTask配合Thread
FutureTask源代码内部也是继承了Runnable 接口,不过他存在Future的线程执行返回结果。

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask task=new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {
                System.out.println("执行Callable");
                Thread.sleep(100);
                return 100;
            }
        });
        Thread t=new Thread(task,"cal1");
        t.start();
        //执行task的get方法会等待线程执行完成之后。获取返回结果
        System.out.println(task.get());
    }

java项目在linux中查看进程的方式,命令如下:
ps -fe || grep java
jps
linux查看线程方式
top -h -p 线程ID
jstack 线程ID
也可以使用jconsole远程连接监控线程

线程运行的原理:
栈和栈帧
栈内存是由多个栈帧组成。
栈内存的方式是 先进后出。

创建线程需要分配时间调度切换,开启线程和关闭线程
线程池的线程在于开启线程以后不会释放线程栈空间。

线程是稀缺资源,他是创建与销毁是一个相对偏重且消耗资源的操作,而java线程依赖于内核线程,要进行操作系统状态切换
为避免资源过度消耗需要设法重用线程执行多个任务,线程池就是一个负责对线程进行统一分配。调度与监控

线程池工具类Executor
ExecutorService service=new newCachedThreadPool();
service.execute(Runnable任务);
newCachedThreadPool   最快  有多少任务会创建多少线程,线程过多会让CPU达到100%
newFixedThreadPool    较慢慢    创建线程数是传入的数量 ,只能执行固定的线程数量,多余的任务存放在队列中,任务过多会出现内存溢出
newSingleThreadExecutor 最慢   只会创建一个线程。多余的任务存放在队列中,任务过多会出现内存溢出
不推荐使用上面现有的创建线程池方式,下面是使用自定义线程池方式:
ThreadPoolExecutor threadPoolExecutor =new ThreadPoolExecutor('核心线程数','最大线程数','时间策略','等待队列')

线程池处理任务顺序:
核心线程
队列排队
非核心线程
都满了,触发拒绝策略


redis实现分布式锁:
命令
setnx   key  value
值在键key不存在的情况下,将键key的值设置为value

使用redis锁要注意使用finally释放锁
需要设置超时时间,但是设置超时时间的时候需要保证存锁的过程中是一起执行的。

由于设置了超时时间,这时候会出现时间到了代码没执行完,另外线程B进来了。然后线程A执行了finally释放了线程B的锁
所以这时候需要在value里面放入在这个线程生成的uuid,释放锁定的时候判断是否uuid是否还是一样的。

设置超时时间,可以加锁以后,开辟一个线程,给锁重置时间。不过这里开辟线程存在较多的问题。
这时候我们可以直接引用redisson工具包进行加锁。

如果要对锁提高性能,对库存进行分段存储,分段锁。比如1个商品100数量
可以拆分成10个商品每个商品10个数量

native关键字
凡是带来native关键字的,说明java的作用达不到了,去调用底层C语言库
会进入本地方法栈
调用本地方法本地栈jni
JNI作用:扩展java的作用,融合不同的编程语言为java所用。

作用:volatile关键字,改共享变量的可见性

  当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主内存,当有其他线程读取时,它会去内存中读取。

通过缓存一致性协议。每个数据存在一种状态。

在jmm内存模型中划分为:

主内存-》缓存内存->工作内存

当我们创建一个普通变量时,这个变量放在主内存中。使用过程中会放在缓存内存中。

当开启一个线程进行时候的时候,会将变量复制一份,放在自己的工作内存中执行。

这时候如果现在A修改了加了volatile的变量,会通过监听机制,广播其他线程,告诉他们我进行了修改。

其他线程就会将自己工作线程中的变量,状态修改为失效状态。再次使用的时候,发现已经失效,会从新去主内存中查询。

volatile能防止指令重排,但是不能保证原子性

在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。

 

AQS

大部分同步锁是基于AQS实现的。是JDK提供的一个同步框架,

内部维护着一个FIFO双向队列,即CLH同步队列

AQS依赖它的同步管理

如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值