• Synchronized锁1


     Synchronized

    在java语言中存在两种内建的synchronized语法:synchronized语句和synchronized方法。synchronized将并行改为串行,当然会影响程序的执行效率,执行速度会受到影响。其次synchronized操作线程的堵塞,也就是由操作系统控制CPU的内核进行上下文的切换,这个切换本身也是耗时的。所以使用synchronized关键字会降低程序的运行效率。 

    三个售票窗口同时出售20张票

    1. public class Test1 {
    2. public static void main(String[] args) {
    3. for(int i=1;i<=3;i++) {
    4. new 售票线程(i+"号窗口").start();
    5. }
    6. }
    7. }
    8. class 售票线程 extends Thread{
    9. private String name;
    10. private static Integer count=20;//票池,static保证多个线程对象共享一个票池
    11. private static final String aaa="bbbb";
    12. public 售票线程(String name) {
    13. this.name = name;
    14. }
    15. @Override
    16. public void run() {
    17. while(count>0) {
    18. // System.out.println(this.name+count+"开始售票");
    19. try {
    20. Thread.sleep(1000);
    21. } catch (InterruptedException e) {
    22. e.printStackTrace();
    23. }
    24. synchronized (aaa) {
    25. if(count>0) {
    26. System.out.println(this.name+"售出第 "+count+" 号票");
    27. count--;
    28. // System.out.println(this.name+":"+count);
    29. }else {
    30. System.out.println(this.name+"票已售尽");
    31. }
    32. // System.out.println(this.name+count+"结束售票");
    33. }
    34. }
    35. }
    36. }

    Synchronized用于实现同步处理,保证共享数据的安全性


    数据有安全性问题的原因:1、共享数据 2、修改数据

    Synchronized相对于volatile是重量级的线程安全的方法,可以保证3大特性:原子性、可见性、有序性


    synchronized将并行改为串行
             -用于静态方法,锁对象为当前类

                    public synchronized static void pp(){}
            -用于非静态方法,锁对象为当前类的对象
                    public synchronized void pp(){}
            -用于代码块,锁对象为指定的对象  该对象可以自定义
                    synchronized(obj){}

    同步代码块

    1. import java.util.concurrent.locks.Lock;
    2. //同步代码块
    3. public class A {
    4. public static void main(String[] args) {
    5. for(int i=1;i<=3;i++) {
    6. new MyThread(i+"号窗口").start();
    7. }
    8. }
    9. }
    10. class MyThread extends Thread{
    11. private String name;
    12. private static int counter=20;
    13. private static final String LOCK="bbbb";
    14. public MyThread(String name) {
    15. this.name=name;
    16. }
    17. @Override
    18. public void run() {
    19. while(counter>0) {
    20. try {
    21. Thread.sleep(100);
    22. } catch (InterruptedException e) {
    23. e.printStackTrace();
    24. }
    25. synchronized (LOCK) {//锁的数量一定要比资源少,要把资源锁住,用name不可以,因为name是3个窗口,不能锁住,锁有一把;只要是引用类型都可以,
    26. if(counter>0) {
    27. System.out.println(this.name+"售出第"+counter+"号票");
    28. synchronized (LOCK) {
    29. counter--;
    30. }
    31. System.out.println(this.name+":"+counter);
    32. }else {
    33. System.out.println(this.name+":"+"票已售尽");
    34. }
    35. }
    36. }
    37. }
    38. }

    同步方法

    1. public class A2 {
    2. public static void main(String[] args) throws Exception {
    3. NumOper no=new NumOper(100);
    4. Thread[] th=new Thread[4];
    5. for (int i = 0; i < 2; i++) {
    6. th[i*2]=new Thread(() -> {
    7. for(int k=0;k<50;k++) {
    8. no.add();
    9. }
    10. });
    11. th[i*2].start();
    12. th[i*2+1]=new Thread(() -> {
    13. for(int k=0;k<50;k++) {
    14. no.sub();
    15. }
    16. });
    17. th[i*2+1].start();
    18. }
    19. for(Thread tmp:th)
    20. tmp.join();
    21. System.out.println("Main:"+no.getNum());
    22. }
    23. }
    24. /*
    25. * 以new出来的NumOper对象充当锁,当前对象内的synchronized方法在不同线程调用时互斥,
    26. * 但是可以直接访问非synchronized方法
    27. *
    28. * 注意synchronized允许持有锁的线程重入
    29. */
    30. class NumOper {
    31. private int num;
    32. public NumOper(int num) {//synchronized不能添加到构造器上
    33. this.num = num;
    34. }
    35. public synchronized void add() {
    36. System.out.println(Thread.currentThread() + "Thread......begin" + this.num);
    37. this.num++;
    38. // sub();
    39. System.out.println(Thread.currentThread() + "Thread......end" + this.num);
    40. }
    41. public synchronized void sub() {
    42. System.out.println(Thread.currentThread() + "Thread......begin" + this.num);
    43. this.num--;
    44. System.out.println(Thread.currentThread() + "Thread......end" + this.num);
    45. }
    46. public int getNum() {
    47. return this.num;
    48. }
    49. }

    同步静态方法

    统计指定类的创建次数 ,代码如下:

    1. public class A3 {
    2. public static void main(String[] args) {
    3. for(int i=0;i<5;i++) {
    4. new Thread(()->{
    5. for(int k=0;k<10;k++) {
    6. new S3();
    7. }
    8. }).start();
    9. }
    10. try {
    11. Thread.sleep(10000);
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. }
    15. System.out.println(S3.getCounter());//
    16. }
    17. }
    18. class S3{
    19. private static int counter=0;
    20. public S3() {
    21. add();
    22. }
    23. private synchronized static void add() {//static 不可以用this
    24. System.out.println(Thread.currentThread()+"开始创建操作"+counter);
    25. counter++;
    26. System.out.println(Thread.currentThread()+"完成创建操作"+counter);
    27. }
    28. public static int getCounter() {
    29. return counter;
    30. }
    31. }

    使用类锁,所以不管new了多少个对象,都可以得到互斥的效果

    1. public class A4 {
    2. public static void main(String[] args) {
    3. new Thread(()->{
    4. for(int i=0;i<20;i++) {
    5. S4 ss=new S4();
    6. ss.pp1();
    7. }
    8. }).start();
    9. new Thread(()->{
    10. for(int i=0;i<20;i++) {
    11. S4 ss=new S4();
    12. ss.pp1();
    13. }
    14. }).start();
    15. }
    16. }
    17. class S4{
    18. public synchronized static void pp1() {
    19. System.out.println(Thread.currentThread()+"...begin...");
    20. try {
    21. Thread.sleep(100);
    22. } catch (InterruptedException e) {
    23. e.printStackTrace();
    24. }
    25. System.out.println(Thread.currentThread()+"...end...");
    26. }
    27. public void pp2() {}
    28. }

    使用的是对象锁,所以只能new一个对象,都可以得到互斥的效果。如果创建多个则不能达到互斥目的

    1. public class A41 {
    2. public static void main(String[] args) {
    3. S41 ss=new S41();
    4. new Thread(()->{
    5. // S41 ss=new S41();
    6. for(int i=0;i<20;i++) {
    7. // S41 ss=new S41();
    8. ss.pp2();
    9. }
    10. }).start();
    11. new Thread(()->{
    12. // S41 ss=new S41();
    13. for(int i=0;i<20;i++) {
    14. // S41 ss=new S41();
    15. ss.pp2();
    16. }
    17. }).start();
    18. }
    19. }
    20. //类S4为锁对象
    21. class S41{
    22. public synchronized static void pp1() {
    23. System.out.println(Thread.currentThread()+"...begin...");
    24. try {
    25. Thread.sleep(100);
    26. } catch (InterruptedException e) {
    27. e.printStackTrace();
    28. }
    29. System.out.println(Thread.currentThread()+"...end...");
    30. }
    31. public synchronized void pp2() {
    32. System.out.println(Thread.currentThread()+"...begin...");
    33. try {
    34. Thread.sleep(100);
    35. } catch (InterruptedException e) {
    36. e.printStackTrace();
    37. }
    38. System.out.println(Thread.currentThread()+"...end...");
    39. }
    40. public synchronized void pp3() {
    41. System.out.println(Thread.currentThread()+"...begin...");
    42. try {
    43. Thread.sleep(100);
    44. } catch (InterruptedException e) {
    45. e.printStackTrace();
    46. }
    47. System.out.println(Thread.currentThread()+"...end...");
    48. }
    49. }

    使用的是不同的锁,所以thread0和thread1不能达到互斥的效果。

    1. public class A42 {
    2. public static void main(String[] args) {
    3. S42 ss=new S42();
    4. new Thread(()->{
    5. // S41 ss=new S41();
    6. for(int i=0;i<20;i++) {
    7. // S41 ss=new S41();
    8. // ss.pp2();//非static方法 --对象锁 ss
    9. ss.pp3();
    10. }
    11. }).start();
    12. new Thread(()->{
    13. // S41 ss=new S41();
    14. for(int i=0;i<20;i++) {
    15. // S41 ss=new S41();
    16. ss.pp1();//static方法 --类锁 S42.class
    17. ss.pp4();
    18. }
    19. }).start();
    20. }
    21. }
    22. //类S4为锁对象
    23. class S42{
    24. public synchronized static void pp1() {
    25. System.out.println(Thread.currentThread()+"...begin...");
    26. try {
    27. Thread.sleep(100);
    28. } catch (InterruptedException e) {
    29. e.printStackTrace();
    30. }
    31. System.out.println(Thread.currentThread()+"...end...");
    32. }
    33. public synchronized void pp2() {
    34. System.out.println(Thread.currentThread()+"...begin...");
    35. try {
    36. Thread.sleep(100);
    37. } catch (InterruptedException e) {
    38. e.printStackTrace();
    39. }
    40. System.out.println(Thread.currentThread()+"...end...");
    41. }
    42. public synchronized static void pp3() {
    43. System.out.println(Thread.currentThread()+"...begin...");
    44. try {
    45. Thread.sleep(100);
    46. } catch (InterruptedException e) {
    47. e.printStackTrace();
    48. }
    49. System.out.println(Thread.currentThread()+"...end...");
    50. }
    51. public synchronized static void pp4() {
    52. System.out.println(Thread.currentThread()+"...begin...");
    53. try {
    54. Thread.sleep(100);
    55. } catch (InterruptedException e) {
    56. e.printStackTrace();
    57. }
    58. System.out.println(Thread.currentThread()+"...end...");
    59. }
    60. }

    锁对象不一样会导致锁不住,一个是类锁,一个是对象锁

    1. public class A44 {
    2. public static void main(String[] args) {
    3. S44 ss=new S44();
    4. new Thread(()->{
    5. // S44 ss=new S44();
    6. for(int i=0;i<20;i++) {
    7. // S41 ss=new S41();
    8. // ss.pp2();//非static方法 --对象锁 ss
    9. ss.pp3();
    10. }
    11. }).start();
    12. new Thread(()->{
    13. // S44 ss=new S44();
    14. for(int i=0;i<20;i++) {
    15. // S41 ss=new S41();
    16. ss.pp2();//非static方法 --对象锁 ss
    17. }
    18. }).start();
    19. new Thread(()->{
    20. // S44 ss=new S44();
    21. for(int i=0;i<20;i++) {
    22. // S41 ss=new S41();
    23. ss.pp1();//static方法 --类锁 S42.class
    24. }
    25. }).start();
    26. new Thread(()->{
    27. // S44 ss=new S44();
    28. for(int i=0;i<20;i++) {
    29. // S41 ss=new S41();
    30. ss.pp4();
    31. }
    32. }).start();
    33. }
    34. }
    35. //类S4为锁对象
    36. class S44{
    37. public synchronized static void pp1() {
    38. System.out.println(Thread.currentThread()+"...begin...");
    39. try {
    40. Thread.sleep(100);
    41. } catch (InterruptedException e) {
    42. e.printStackTrace();
    43. }
    44. System.out.println(Thread.currentThread()+"...end...");
    45. }
    46. public synchronized void pp2() {
    47. System.out.println(Thread.currentThread()+"...begin..."+Thread.currentThread().getName());
    48. try {
    49. Thread.sleep(100);
    50. } catch (InterruptedException e) {
    51. e.printStackTrace();
    52. }
    53. System.out.println(Thread.currentThread()+"...end..."+Thread.currentThread().getName());
    54. }
    55. public synchronized static void pp3() {
    56. System.out.println(Thread.currentThread()+"...begin...");
    57. try {
    58. Thread.sleep(100);
    59. } catch (InterruptedException e) {
    60. e.printStackTrace();
    61. }
    62. System.out.println(Thread.currentThread()+"...end...");
    63. }
    64. public synchronized static void pp4() {
    65. System.out.println(Thread.currentThread()+"...begin...");
    66. try {
    67. Thread.sleep(100);
    68. } catch (InterruptedException e) {
    69. e.printStackTrace();
    70. }
    71. System.out.println(Thread.currentThread()+"...end...");
    72. }
    73. }
  • 相关阅读:
    IDEA使用技巧
    笔试强训第24天--(年终奖 + 迷宫问题)
    卡码网语言基础课 |出现频率最高的字母
    Socket作用及其使用
    使用FCEUX调试器寻找并修改游戏初始物品
    即时通讯场景下安全合规的实践和经验
    基于神经网络的系统辨识,神经网络与图像识别
    洛谷月赛 P5588 小猪佩奇爬树
    如何实现前端单页面应用(SPA)?
    【Vue3】图片未加载成功前占位
  • 原文地址:https://blog.csdn.net/tiger_root/article/details/126589447