• 浅谈Java多线程的同步问题 【转】


    多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。

    下面以一个简单的实例来进行对比分析。实例要完成的工作非常简单,就是创建10个线程,每个线程都打印从0到99这100个数字,我们希望线程之间不会出现交叉乱序打印,而是顺序地打印。

    先来看第一段代码,这里我们在run()方法中加入了synchronized关键字,希望能对run方法进行互斥访问,但结果并不如我们希望那样,这是因为这里synchronized锁住的是this对象,即当前运行线程对象本身。代码中创建了10个线程,而每个线程都持有this对象的对象锁,这不能实现线程的同步。

     1 代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.vista;
     2 
     3 class MyThread implements java.lang.Runnable
     4 {
     5     private int threadId;
     6 
     7     public MyThread(int id)
     8     {
     9         this.threadId = id;
    10     }
    11     @Override
    12     public synchronized void run() 
    13     {
    14         for (int i = 0; i < 100; ++i)
    15         {
    16             System.out.println("Thread ID: " + this.threadId + " : " + i);
    17         }
    18     }
    19 }
    20 public class ThreadDemo
    21 {
    22     /**
    23      * @param args
    24      * @throws InterruptedException 
    25      */
    26     public static void main(String[] args) throws InterruptedException
    27     {
    28         for (int i = 0; i < 10; ++i)
    29         {
    30             new Thread(new MyThread(i)).start();
    31             Thread.sleep(1);
    32         }
    33     }
    34 }

          从上述代码段可以得知,要想实现线程的同步,则这些线程必须去竞争一个唯一的共享的对象锁。

          基于这种思想,我们将第一段代码修改如下所示,在创建启动线程之前,先创建一个线程之间竞争使用的Object对象,然后将这个Object对象的引用传递给每一个线程对象的lock成员变量。这样一来,每个线程的lock成员都指向同一个Object对象。我们在run方法中,对lock对象使用synchronzied块进行局部封锁,这样就可以让线程去竞争这个唯一的共享的对象锁,从而实现同步。

     1 代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.vista;
     2 
     3 class MyThread implements java.lang.Runnable
     4 {
     5     private int threadId;
     6     private Object lock;
     7     public MyThread(int id, Object obj)
     8     {
     9         this.threadId = id;
    10         this.lock = obj;
    11     }
    12     @Override
    13     public  void run() 
    14     {
    15         synchronized(lock)
    16         {
    17             for (int i = 0; i < 100; ++i)
    18             {
    19                 System.out.println("Thread ID: " + this.threadId + " : " + i);
    20             }
    21         }
    22     }
    23 }
    24 public class ThreadDemo
    25 {
    26     /**
    27      * @param args
    28      * @throws InterruptedException 
    29      */
    30     public static void main(String[] args) throws InterruptedException
    31     {
    32         Object obj = new Object();
    33         for (int i = 0; i < 10; ++i)
    34         {
    35             new Thread(new MyThread(i, obj)).start();
    36             Thread.sleep(1);
    37         }
    38     }
    39 }

    从第二段代码可知,同步的关键是多个线程对象竞争同一个共享资源即可,上面的代码中是通过外部创建共享资源,然后传递到线程中来实现。我们也可以利用类成员变量被所有类的实例所共享这一特性,因此可以将lock用静态成员对象来实现,代码如下所示:

     1 代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.vista;
     2 
     3 class MyThread implements java.lang.Runnable
     4 {
     5     private int threadId;
     6     private static Object lock = new Object();
     7     public MyThread(int id)
     8     {
     9         this.threadId = id;
    10     }
    11     @Override
    12     public  void run() 
    13     {
    14         synchronized(lock)
    15         {
    16             for (int i = 0; i < 100; ++i)
    17             {
    18                 System.out.println("Thread ID: " + this.threadId + " : " + i);
    19             }
    20         }
    21     }
    22 }
    23 public class ThreadDemo 
    24 {
    25     /**
    26      * @param args
    27      * @throws InterruptedException 
    28      */
    29     public static void main(String[] args) throws InterruptedException
    30     {
    31         for (int i = 0; i < 10; ++i)
    32         {
    33             new Thread(new MyThread(i)).start();
    34             Thread.sleep(1);
    35         }
    36     }
    37 }

    再来看第一段代码,实例方法中加入sychronized关键字封锁的是this对象本身,而在静态方法中加入sychronized关键字封锁的就是类本身。静态方法是所有类实例对象所共享的,因此线程对象在访问此静态方法时是互斥访问的,从而可以实现线程的同步,代码如下所示:

     1 代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.vista;
     2 
     3 class MyThread implements java.lang.Runnable
     4 {
     5     private int threadId;
     6     
     7     public MyThread(int id)
     8     {
     9         this.threadId = id;
    10     }
    11     @Override
    12     public  void run() 
    13     {
    14         taskHandler(this.threadId);
    15     }
    16     private static synchronized void taskHandler(int threadId)
    17     {
    18         for (int i = 0; i < 100; ++i)
    19         {
    20             System.out.println("Thread ID: " + threadId + " : " + i);
    21         }
    22     }
    23 }
    24 public class ThreadDemo
    25 {
    26     /**
    27      * @param args
    28      * @throws InterruptedException 
    29      */
    30     public static void main(String[] args) throws InterruptedException
    31     {
    32         for (int i = 0; i < 10; ++i)
    33         {
    34             new Thread(new MyThread(i)).start();
    35             Thread.sleep(1);
    36         }
    37     }
    38 }

    作者:洞庭散人

    出处:http://phinecos.cnblogs.com/    

    本博客遵从Creative Commons Attribution 3.0 License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。
  • 相关阅读:
    修改nuget包默认存放路径,避免增加C盘的负担
    .Net Core 3.0 (一):安装Vs2019
    .NET Core 学习资料
    SQLSERVER查询整个数据库中某个特定值所在的表和字段的方法
    MySql 时间查询
    如何设置IIS程序池的回收时间,才能最大程度的减少对用户的影响?
    SqlServer 获取工作日(周六、周日休息,周六日不休息,周六不休息)
    SQL Server 删除数据库中表数据
    SQL Server 删除数据库所有表和所有存储过程
    摘要
  • 原文地址:https://www.cnblogs.com/disneyland/p/4545300.html
Copyright © 2020-2023  润新知