java的并发编程需要注意的问题

yield方法,意思是使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。

当多线程的情况下,遇到共享变量的情况下,为了保持数据的一致性,可以采用synchronized关键字,可以加方法上,表示对这个对象this加锁,但是效率不高,可以用synchronized代码段,只对共享变量的地方加锁,还有如果共享变量是数字时,用Atomic关键字修饰变量。可以不用synchronized。这个对象是java并发包给我提供的类,里面包含有加减运算

volatile关键字 ,cpu是有缓存的,当变量的值已经改变,但是cpu还是从缓存中取值就会出现错误,volatile关键字就是告诉cpu必须从内存中取值,不走缓存,volatile可以实现可见性,不能实现原子性问题。 不能解决并发问题
synchronize可以实现可见性和原子性问题。 可以解决并发问题

ThreadLocal 作用是和当前线程绑定,这个对象有个get,set方法,可以把对象放进去,不会出现多线程争夺共享变量的情况

同步容器: vector hashtable Collections.synchronize() 这些是一些老的api,源码基本上都是采用synchronize来实现的,很笨重。

**并发容器:**ConcurrentHashMap 分段锁 java 1.5提供的api
ConcurrentHashMap map = new ConcurrentHashMap ();
map .putIfAbsent(1,2) 这个方法是 如果key不存在就放进去,存在就返回none。

CopyOnWriteArrayList /Set 这两个实现的基本原理是操作的时候先上一把锁,然后把共享资源复制一份,然后再复制的资源里面搞搞搞,使用的场景是读的多,写的少的操作

BlocakingQueue 阻塞队列。有两个方法,一个put放东西,take取东西 队列特点就是先进先出,就像一根水管,往里面塞东西。先进的肯定先出。

闭锁 栅栏 信号量

闭锁的意思就是当线程都执行完了,才放行,如何实现呢?CountDownLatch 倒计时的意思

CountDownLatch  latch = new  CountDownLatch (2);   //表示有两个线程

latch.countDown()      //一般线程执行完之后调用这个方法,表示这个线程执行完了

latch.awit()          //这个方法必须是latch里面的线程都执行完了,才放行。

栅栏 的相当于水坝的意思,就是有个线程达到某种状态之后,然后这个线程才能继续操作

CyclicBarrier barrier = new CyclicBarrier (4)

barrier.await()   //只有当wait的线程等于4,才会继续往下走。不然都得等着。

信号量 生产者和消费者人数不对等的情况下,比如5个机器,8个人要用,刚开始每人一个,然后有人释放掉,另外一个工人就补上、

int t=8  //8个工人
Semaphore semaphore = new  Semaphore(5) //机器的数目

semaphore.acquire();   //意思是从5台机器中获取一个

semaphore.release();    //意思是机器释放,下一个工人就顶上。

线程池

当遇到并发时,肯定需要用到线程池,因为你不可能没来一次请求就创建一个线程吧,那样的话你服务器会受不了的。

Executor executor = Executors.newFixedThreadPool(100);//意思是这个线程池有100个线程

executor.execute(线程)  //把线程扔进去,就可以了。他就执行线程的start方法。

Executor的实现类ExecutorService   这个类是Executor的实现类,里面有几个非常常用的方法。

定时任务

java提供的Timer这个类可以实现定时任务。
注意:timer有两个缺点,一个是当有多个任务的时候,比如原本第二个任务是1秒之后执行,但是第一个任务执行两秒才结束,那么第二个任务就必须等第一个任务执行完再执行。
还有一个就是当第一个任务报错之后,timer里面的任务全都挂掉了。这是非常严重的后果。

Timer timer=new Timer();
timer.schedule(线程,1000);//意思是1000毫秒之后执行线程


//如何解决这个问题呢?
//创建一个可调度的线程池
ScheduledExecutorService ExecutorService = Executors.newScheduleduledThreadPool(100);
EsxecutorService.schedule(线程,1000,TimerUnit.MILLISECONDS)//最后一个是指明1000的时间单位,这里是毫秒

死锁

嵌套锁会造成死锁
解决办法:1避免嵌套锁,2嵌套锁的顺序,3引入超时机制

Lock锁

是java1.5提供的一种锁,可以很灵活的控制。

Lock lock=new ReentrantLock();     //创建一个可重入锁

//主要有两个方法
lock.lock();      //加锁
locak.unlock();  //解锁
ReentrantReadWriteLock rwl= new  ReentrantReadWriteLock() ;  //创建一个既可以读又可以写的锁
rwl.writeLock().lock()   //创建一个写锁, 只能一个线程进来
rwl.writeLock().unlock() //释放写锁

rwl.readLock().lock()   //创建一个读锁, 可以有多个线程进来
rwl.readLock().unlock() //释放读锁

悲观锁和乐观锁 —–数据库层面的

悲观锁:只有一个线程在操作,不管读还是写,直接把这个表锁住了,其他线程进不来,实现语句
后面加for update

select * from user  for update

乐观锁:表中加version字段。

分布式锁:redis zk

发布了281 篇原创文章 · 获赞 50 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/lzh657083979/article/details/79365217