目录
乐观锁
介绍
- 悲观锁:上来就加锁,没有安全感。每次只能一个线程进入访问完毕后,再解锁。线程安全,性能较差!
- 乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。线程安全,性能较好。
需求
1个变量,100个线程,每个线程对其加100次。
public class MyRunnable implements Runnable{
private int count; //记录浏览人次
@Override
public void run() {
//100次
for (int i = 0; i < 100; i++) {
synchronized (this){
System.out.println(Thread.currentThread().getName() +
" count =======>" + (++count));
}
}
}
}
public class Test1 {
public static void main(String[] args) {
//需求1:1个变量,100个线程,每个线程对其加100次。
Runnable target = new MyRunnable();
for(int i = 1; i <= 100;i++){
new Thread(target).start();
}
}
}
运行结果:
这段代码一开始就上了锁,属于典型的悲观锁,所以是一个一个地去竞争锁,其他进程都要排队;排队次数太多,性能很差。
因为性能太差,所以我们不用悲观锁,采用CAS算法(比较和交换算法)。
CAS算法
这个算法的基本思路:
- 先拿到数据初始的值,将其修改之后;
- 再回到数据初始地址,比较初始值是否被修改;
- 如果被修改,则撤销这次修改值的操作;
- 如果未被修改,则执行这次修改操作。
代码示例:
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnable2 implements Runnable{
//整数修改的乐观锁:原子类实现的。
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
//100次
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() +
" count ========>" + count.incrementAndGet() );
}
}
}
多线程练习题
目标:有100份礼品,小红,小明两人同时发送,当剩下的礼品小于10份的时候则不再送出。
利用多线程模拟该过程并将线程的名称打印出来。并最后在控制台分别打印小红,小明各自送出多少份礼物。
线程类
import java.util.List;
import java.util.Random;
public class SendThread extends Thread{
private List<String> gift;
private int count;
public SendThread(List<String> gift,String name){
super(name);
this.gift = gift;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
//小明、小红 发礼物出去
//实现线程安全问题
//注意:锁必须唯一
Random r = new Random();
while(true){
synchronized (gift){
if(gift.size() < 10){
break;
}
String rs = gift.remove(r.nextInt(gift.size()));
System.out.println(name + "发出了:" + rs);
count++;
}
}
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
main
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Demo1 {
public static void main(String[] args) throws Exception {
//目标:有100份礼品,小红,小明两人同时发送,当剩下的礼品小于10份的时候则不再送出。
//利用多线程模拟该过程并将线程的名称打印出来。并最后在控制台分别打印小红,小明各自送出多少份礼物。
//1.拿100份礼品到程序中来
List<String> gift = new ArrayList<>();
String[] names = {"口红","包包","鲜花","手绳","手镯","手表"};
Random r = new Random();
for (int i = 0; i < 100; i++) {
gift.add(names[r.nextInt(names.length)] + (i + 1) ); //随机添加礼物 + 礼物的序号
}
System.out.println(gift);
//2.定义线程类,创建线程对象,去集合中拿礼物给别人
SendThread xm = new SendThread(gift,"小明");
xm.start();
SendThread xh = new SendThread(gift,"小红");
xh.start();
xm.join();
xh.join();
System.out.println("小明发出了:" + xm.getCount() + "份礼物");
System.out.println("小红发出了:" + xh.getCount() + "份礼物");
}
}
END
学习自:黑马程序员——Java课程