线程锁
为什么需要线程锁?
- 对于多个线程同时执行一个相同的操作就会对数据进行错误操作、导致线程不安全。
- 实现等待和唤醒机制。
线程锁的作用
就是当某一个线程拿到这个锁的时候其他线程是无法拿到这把锁,就不会对于数据的操作出现数据偏差。
对于多个线程
锁的实现
实现锁之前必须要有两个条件(1、共享 2、互斥)加锁的对象必定是多个线程共享的,获得锁的对象必定是互斥的,该线程获得锁其他线程不能获得锁的。
- 在线程里可直接加 synchronized 对方法、对象 、以及代码段进行加锁。
/**
* 线程内部锁机制
**/
public class lockSynchronized{
// 首先新建两个线程 对同一常量进行操作
private int count = 0;
public static void main(String[] args) throws InterruptedException {
Thread[] th2 =new Thread [10];
for (int i = 0 ; i < 10 ;i++){
th2[i] = new Thread(new Threadlock());
th2[i].start();
}
Thread.sleep(1000);
}
//通过多线程访问 同一个count 做++ 最终结果 会小于或者 等于10 如果加上synchronized
public void add(){
count++;
System.out.println(1+":"+count);
}
// 新建一个线程
class Threadlock extends Thread {
@Override
public void run(){
// 对于count ++ ;
add();
}
}
}
上述代码在没有加锁的情况下会出现数据错乱。 控制台有可能会输出为这样的
1:1
1:2
1:3
1:4
1:5
1:6
1:7
1:8
1:10 // 正常的这里应该是 9
1:10
现在来实现几种基本加锁的方式,在上面的add()方法;加synchronized
// synchronize 是重量级锁 所以直接加在方法上很是消耗性能
public synchronized void add(){
count++;
System.out.println(1+":"+count);
}
// 通过对象来进行加锁 ,只是这个对象需要是共享 的任意对象都可以。
public void add(){
synchronized (SyncDemo.class) {
count++;
System.out.println(1+":"+count);
}
}
- 实现生产者和消费者
什么叫生产者和消费者 ,比如在餐厅吃饭,你是客户就是消费者,厨师就是生产者。
1、 厨师在进行生产时 ,消费者需要等待。
2、 厨师制作食物完成,那么没有新的消费者那么厨师需要等待新的消费。
3、 所以我们需要一个中间收营员,来提醒厨师和顾客。
/**
* 创建一个收营员的类
**/
public class Cashier{
// 定义一个厨师最多能够制作多少份
private int MAX_SIZE =10;
// 定义一个容器
public BlockingQueue<String> queue= new LinkedBlockingDeque<String>;
/**
* 客户点餐
**/
public void add(String food){
synchronized(Cashier.class){
while (true){
try{
if(queue.siez()>MAX_SIZE){
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
this.notify();
queue.offer(food);
}
}
/**
* 客户取餐
**/
public void delet(){
synchronized(Cashier.class){
while (true){
try{
if(queue.isEmpty()){
//是空的时候进行等待
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
String d = queue.take();
this.notify();// 唤醒 点餐
System.out.print("消费者消费了"+d);
}
}
/**
* 客户线程 消费线程
**/
public class Customer extends Thread {
// 创建仓库对象
private static Cashier cashier = new Cashier();
public Customer (Cashier cashier){
this.cashier = cashier;
}
@Override
public void run(){
// 如果对象不为空
if(!cashier.queue.isEmpty()){
cashier.delet();
}
}
}
/**
* 厨师线程 生产线程
**/
public class Cook extends Thread {
// 创建仓库对象
private static Cashier cashier = new Cashier();
private String food;
public Cook (Cashier cashier,String food){
this.cashier = cashier;
}
@Override
public void run(){
// 如果对象为空
if(cashier.queue.isEmpty()){
cashier.add(food);
}
}
}
public class Test(){
@Test
public void threadTest(){
// 中间对象
Cashier cashier = new Cashier();
Cook cook = new Cook (cashier,"aa");
cook.start();
Customer customer = new Customer(cashier);
customer.start();
}
}
ReentrantLock 类
在jdk 1.5 中新增加的ReentrantLock 类同样也可以达到这样的效果,并且在功能上有更多的加强,使用上更加的灵活。
package thread.synchronizLock;
import org.junit.Test;
import java.util.concurrent.locks.ReentrantLock;
public class SyncDemo {
// 首先新建两个线程 对同一常量进行操作
private volatile int count = 0;
// 创建lock对象
private ReentrantLock lock = new ReentrantLock();
@Test
public void test() throws InterruptedException {
Threadlock1 th1 =new Threadlock1 ();
Thread[] th2 =new Thread [10];
// th1.start();
for (int i = 0 ; i < 10 ;i++){
th2[i] = new Thread(new Threadlock());
th2[i].start();
th2[i] = new Thread(new Threadlock1 ());
th2[i].start();
}
Thread.sleep(1000);
}
public void add() {
try {
// 加锁
lock.lock();
count++;
System.out.println(1 + ":" + count);
}finally {
// 解锁
lock.unlock();
}
}
class Threadlock extends Thread {
@Override
public void run(){
add();
}
}
class Threadlock1 extends Thread {
@Override
public void run(){
for (int i = 0;i < 10 ; i++ ) {
add();
}
}
}
}