多线程synchronized与lock

69 阅读3分钟

一、synchronized关键字

在多线程中,在资源共享的情况下会出现安全问题

  • 使用Runnable接口实现多线程。
  • 创建RunnableTest类,并创建nums私有资源,设置为100
  • 重写run方法,在方法中通过while死循环减少资源
  • 创建测试类RunnableDemo对象,在这里创建两个线程,执行同一资源
public class RunnableDemo implements Runnable {
    private int nums = 30;

    @Override
    public void run() {
        while (true) {
            if(nums < 0) {
                break;
            } else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                nums--;
                System.out.println(Thread.currentThread().getName()+"的mus的值为"+nums);
            }

        }
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        // 创建参数的对象
        RunnableDemo rb1 = new RunnableDemo();
        // 创建线程对象并传递参数
        Thread t1 = new Thread(rb1);
        Thread t2 = new Thread(rb1);
        // 设置线程名称
        t1.setName("线程1");
        t2.setName("线程2");
        // 开启线程
        t1.start();
        t2.start();
    }
}
  • 执行结果

image.png

同步代码块

通过给代码加锁,让它在同一时间最多一个线程执行这段代码,另外一个等待,上一个线程执行完之后,再执行下一个线程。

它包括两种用法:synchronized 方法和 synchronized 块。可用来给对象和方法或者代码块加锁。当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码

public class RunnableDemo implements Runnable {
    private int nums = 30;
    private Object obj = new Object();
    @Override
    public void run() {
        synchronized (obj) {
            while (true) {
                if(nums <= 0) {
                    break;
                } else {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    nums--;
                    System.out.println(Thread.currentThread().getName()+"的mus的值为"+nums);
                }

            }
        }
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        // 创建参数的对象
        RunnableDemo rb1 = new RunnableDemo();
        // 创建线程对象并传递参数
        Thread t1 = new Thread(rb1);
        Thread t2 = new Thread(rb1);
        // 设置线程名称
        t1.setName("线程1");
        t2.setName("线程2");
        // 开启线程
        t1.start();
        t2.start();
    }
}
  • 执行结果如下

image.png

再修改

如果创建两个参数对象,创建两个线程对象,再次执行线程,这里将nums设置为静态变量,同时Obj也设置为静态变量

public class RunnableDemo implements Runnable {
    private static int nums = 30;
    private static Object obj = new Object();
    @Override
    ....
}

public class RunnableTest {
    public static void main(String[] args) {
        // 创建参数的对象
        RunnableDemo rb1 = new RunnableDemo();
        RunnableDemo rb2 = new RunnableDemo();
        // 创建线程对象并传递参数
        Thread t1 = new Thread(rb1);
        Thread t2 = new Thread(rb2);
        // 设置线程名称
        t1.setName("线程1");
        t2.setName("线程2");
        // 开启线程
        t1.start();
        t2.start();
    }
}
  • 执行结果

image.png

同步方法

就是将synchronized关键字加载静态方法上,如下

public class RunnableDemo implements Runnable {
    private int nums = 30;
    @Override
    public void run() {
        while (true) {
            if ("1".equals(Thread.currentThread().getName())) {
                boolean rs = syncMethod();
                if (rs) {
                    break;
                }
            }
            if ("2".equals(Thread.currentThread().getName())) {
                synchronized (this) {
                    if (nums == 0) {
                        break;
                    } else {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        nums--;
                        System.out.println(Thread.currentThread().getName() + "的mus的值为" + nums);
                    }
                }

            }

        }
    }

    private synchronized boolean syncMethod() {
        if (nums == 0) {
            return true;
        } else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            nums--;
            System.out.println(Thread.currentThread().getName() + "的mus的值为" + nums);
            return false;
        }
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        // 创建参数的对象
        RunnableDemo rb1 = new RunnableDemo();
        // 创建线程对象并传递参数
        Thread t1 = new Thread(rb1);
        Thread t2 = new Thread(rb1);
        // 设置线程名称
        t1.setName("1");
        t2.setName("2");
        // 开启线程
        t1.start();
        t2.start();
    }
}

二、Lock

  • Lock可以实现类似synchronized的线程同步机制,
  • 它更灵活,而且它不是一个关键字,是一个类
  • 它需要手动释放锁,如果不释放,就会出现死锁现象
  • lock可以配置公平策略,实现线程按照先后顺序获取锁
public class RunnableDemo implements Runnable {
    private int nums = 30;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                if (nums <= 0) {
                    break;
                } else {
                    Thread.sleep(100);
                    nums--;
                    System.out.println(Thread.currentThread().getName() + "的mus的值为" + nums);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }


}

public class RunnableTest {
    public static void main(String[] args) {
        // 创建参数的对象
        RunnableDemo rb1 = new RunnableDemo();
        // 创建线程对象并传递参数
        Thread t1 = new Thread(rb1);
        Thread t2 = new Thread(rb1);
        // 设置线程名称
        t1.setName("线程1");
        t2.setName("线程2");
        // 开启线程
        t1.start();
        t2.start();
    }
}