注意:锁一般放在数据容器内

1,方法一:同步代码块:

1,格式:synchronized

  1. synchronized (要锁的对象){
  2. 操作共享数据的代码;
  3. }

2,作用:

给代码块中的代码加锁,解决线程安全问题。

3,原理:

每次只能一个线程获取锁进入,执行完毕以后自动解锁,其他线程才可以进来执行。

4,锁对象的要求:

原则上:锁对象必须是同一个对象。
语法上:任意对象都可以作为锁。

5,使用范例:(实际,就是给代码块内的代码加锁)

没锁的线程是无法执行代码块内的代码的;只有上锁被标记的线程才能进入;

  1. //Window类:
  2. public class Window extends Thread {
  3. //设置共享的变量
  4. private static int tickerNumber = 100;
  5. ***************************************************
  6. //一般开发中会专门使用一个对象作为锁;
  7. //并且要定义为共享对象;
  8. //创建锁对象
  9. private static Object obj = new Object();
  10. //设置线程名称,并指向父类Thread的对应构造器;
  11. public Window(String name) {
  12. super(name);
  13. }
  14. @Override
  15. public void run() {
  16. while (true) {
  17. ******************************************
  18. //使用同步代码块,锁住对象;解决线程安全问题
  19. //注意不要把循环锁上,不然只执行一个对象;
  20. synchronized (obj) {
  21. if (tickerNumber > 0) {
  22. try {
  23. Thread.sleep(100);
  24. }
  25. //捕获sleep异常,这里的代码不需要异常处理代码
  26. catch (InterruptedException e) {
  27. }
  28. tickerNumber--;
  29. System.out.println(getName() + "剩余:" + tickerNumber);
  30. } else {
  31. break;
  32. }
  33. }
  34. //让带锁的对象,休眠一会,避免一个线程对象一直抢锁;
  35. try {
  36. Thread.sleep(10);
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }
  42. }
  43. //main方法类:
  44. public class Text06 {
  45. public static void main(String[] args) {
  46. //创建对象时进行设置线程名称:
  47. Window window1 = new Window("window1");
  48. Window window2 = new Window("window2");
  49. Window window3 = new Window("window3");
  50. //以线程对象启动对应线程
  51. window1.start();
  52. window2.start();
  53. window3.start();
  54. }
  55. }

2,方式二:同步方法:

1,格式:synchronized void

  1. //普通方法:(实例方法)
  2. //使用this作为锁;
  3. public synchronized void 方法名() {
  4. // 操作共享资源的代码
  5. }
  6. //静态方法:
  7. //使用 类名.class 作为锁;
  8. public static synchronized void 方法名() {
  9. // 操作共享资源的代码
  10. }

2,作用:

给方法加锁,解决线程安全问题。

3,原理:(同同步代码块)

每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

4,底层原理:

  1. 1. 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法。
  2. 1. 如果方法是**实例方法**:同步方法默认用**this**作为的锁对象。
  3. 1. 如果方法是**静态方法**:同步方法默认用**类名.class**作为的锁对象。

5,使用范例:

  1. //Window类:
  2. public class Window extends Thread {
  3. private static int tickNumbers = 100;
  4. public Window(String name) {
  5. super(name);
  6. }
  7. @Override
  8. public void run() {
  9. //循环卖票:
  10. while (true) {
  11. //调用同步方法;(静态的)
  12. sales();
  13. //设置线程对象的延迟值,避免一个对象一直抢锁;
  14. try {
  15. Thread.sleep(10);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. if (tickNumbers == 0) {
  20. break;
  21. }
  22. }
  23. }
  24. public static synchronized void sales() {
  25. // System.out.println(Window.class);
  26. //静态对象使用 类名.class 作为对象;
  27. if (tickNumbers > 0) {
  28. try {
  29. Thread.sleep(10);
  30. } catch (InterruptedException e) {
  31. }
  32. tickNumbers--;
  33. //注意:这里的获取线程名称要先获取当前线程对象,因为是静态的,会有多个线程对象,如不先获得,系统无法识别出线程名
  34. System.out.println(Thread.currentThread().getName() + "\t剩余:" + tickNumbers);
  35. }
  36. }
  37. }
  38. //main方法类:
  39. public class Text07 {
  40. public static void main(String[] args) {
  41. //创建线程对象并设置线程名;
  42. Window window1 = new Window("window1");
  43. Window window2 = new Window("window2");
  44. Window window3 = new Window("window3");
  45. window1.start();
  46. window2.start();
  47. window3.start();
  48. }
  49. }

3,方式三:Lock锁:

1,Lock的API :ReentrantLock()

image.png
image.png

2,Lock的介绍:

  1. 1. u为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock,更加灵活、方便。
  2. 1. Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作。
  3. 1. Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象。

3,格式:(lock)

  1. lock.lock();
  2. try {
  3. 操作共享资源代码
  4. } finally {
  5. lock.unlock();
  6. }

4,使用范例:

  1. //main:
  2. public class Text01 {
  3. public static void main(String[] args) {
  4. MyLock myLock1 = new MyLock();
  5. MyLock myLock2 = new MyLock();
  6. myLock1.start();
  7. myLock2.start();
  8. }
  9. }
  10. //mylock类:
  11. public class MyLock extends Thread{
  12. //创建lock
  13. private static Lock lock=new ReentrantLock();
  14. @Override
  15. public void run() {
  16. try {
  17. //获得锁:
  18. lock.lock();
  19. for (int i = 0; i < 10; i++) {
  20. System.out.println(Thread.currentThread().getName()+":"+i);
  21. }
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. } finally {
  25. //释放锁:
  26. //记得在finally里面释放,否则进程一直被一个线程对象拿着锁执行;
  27. lock.unlock();
  28. }
  29. }
  30. }