转载:http://www.cnblogs.com/phinecos/archive/2010/03/13/1684877.html#undefined

多线程的同步依靠的是对象锁机制,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;
     }
     @Override
     public synchronized void run() //错误,无法实现同步
     {
         for (int i = 0; i < 100; ++i)
         {
             System.out.println("Thread ID: " + this.threadId + " : " + i);
         }
     }
 }
 public class ThreadDemo
 {
     /**
      * @param args
      * @throws InterruptedException 
      */
     public static void main(String[] args) throws InterruptedException
     {
         for (int i = 0; i < 10; ++i)
         {
             new Thread(new MyThread(i)).start();
             Thread.sleep(1);
         }
     }
 }
从上述代码段可以得知,要想实现线程的同步,则这些线程必须去竞争一个唯一的共享的对象锁。
      基于这种思想,我们将第一段代码修改如下所示,在创建启动线程之前,先创建一个线程之间竞争使用的Object对象,然后将这个Object对象的引用传递给每一个线程对象的lock成员变量。这样一来,每个线程的lock成员都指向同一个Object对象。我们在run方法中,对lock对象使用synchronzied块进行局部封锁,这样就可以让线程去竞争这个唯一的共享的对象锁,从而实现同步。
class MyThread implements java.lang.Runnable
{
    private int threadId;
    private Object lock;
    public MyThread(int id, Object obj)
    {
        this.threadId = id;
        this.lock = obj;
    }
    @Override
    public  void run() 
    {
        synchronized(lock)//lock由外部产生,引用只有1个,产生竞争关系,线程必须一个一个访问
        {
            for (int i = 0; i < 100; ++i)
            {
                System.out.println("Thread ID: " + this.threadId + " : " + i);
            }
        }
    }
}
public class ThreadDemo
{
    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException
    {
        Object obj = new Object();//外部对象引用
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i, obj)).start();
            Thread.sleep(1);
        }
    }
}

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

class MyThread implements java.lang.Runnable
{
    private int threadId;
    private static Object lock = new Object();//线程内部——静态数据——必须一个一个访问方可
    public MyThread(int id)
    {
        this.threadId = id;
    }
    @Override
    public  void run() 
    {
        synchronized(lock)
        {
            for (int i = 0; i < 100; ++i)
            {
                System.out.println("Thread ID: " + this.threadId + " : " + i);
            }
        }
    }
}
public class ThreadDemo 
{
    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException
    {
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i)).start();
            Thread.sleep(1);
        }
    }
}

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

class MyThread implements java.lang.Runnable
{
    private int threadId;
    
    public MyThread(int id)
    {
        this.threadId = id;
    }
    @Override
    public  void run() 
    {
        taskHandler(this.threadId);
    }
    private static synchronized void taskHandler(int threadId)//静态方法,一次只能有一个其实例访问,线程安全
    {
        for (int i = 0; i < 100; ++i)
        {
            System.out.println("Thread ID: " + threadId + " : " + i);
        }
    }
}
public class ThreadDemo
{
    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException
    {
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i)).start();
            Thread.sleep(1);
        }
    }
}

转载:浅谈Java多线程的同步问题【很好我就留下来,多分共享】的更多相关文章

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

    多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问. 下面以一个简单的实例来进行对比分析.实例要完成的工作非常简单,就是创建10个线程,每个线 ...

  2. 浅谈 Java 多线程(一) --- JMM

    为什么使用多线程 更多的处理器核心数(硬件的发展使 CPU 趋向于更多的核心数,如果不能充分利用,就无法显著提升程序的效率) 更快的响应时间(复杂的业务场景下,会存在许多数据一致性不强的操作,如果将这 ...

  3. 浅谈Java多线程同步机制之同步块(方法)——synchronized

    在多线程访问的时候,同一时刻只能有一个线程能够用 synchronized 修饰的方法或者代码块,解决了资源共享.下面代码示意三个窗口购5张火车票: package com.jikexueyuan.t ...

  4. 浅谈Java多线程

    线程与进程 什么是进程? 当一个程序进入内存中运行起来它就变为一个进程.因此,进程就是一个处于运行状态的程序.同时进程具有独立功能,进程是操作系统进行资源分配和调度的独立单位. 什么是线程? 线程是进 ...

  5. 浅谈Java多线程中的join方法

    先上代码 新建一个Thread,代码如下: package com.thread.test; public class MyThread extends Thread { private String ...

  6. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

  7. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  8. 浅谈java类集框架和数据结构(2)

    继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主 ...

  9. 浅谈Java线程安全

    浅谈Java线程安全 - - 2019-04-25    17:37:28 线程安全 Java中的线程安全 按照线程安全的安全程序由强至弱来排序,我们可以将Java语言中各种操作共享的数据分为以下五类 ...

随机推荐

  1. datejs lib

    // Get today's date Date.today(); // Add 5 days to today Date.today().add(5).days(); // Get Friday o ...

  2. windows 定时任务

    创建定时任务 创建定时任务,时间间隔为1min,开始时间为04:00:00,任务名称为backupSchedule,运行当前目录下的copyData.bat脚本 schtasks /create /s ...

  3. 代码:Masonry 第三方框架

    必备宏使用前提: //define this constant if you want to use Masonry without the 'mas_' prefix #define MAS_SHO ...

  4. objective-c内存管理中autorelease的作用

    //创建自动释放池 @autoreleasepool { //autorelease会将对象放入自动释放池中,并返回该对象本身 //当自动释放池销毁时,将自动调用对象的release方法 Person ...

  5. win8.1企业版更新到win10解决方案

    最近想把自己的win8.1更新成win10,发现月底就要免费更新了,由于我的电脑是企业版,官方不提供企业版的免费升级,所以用电脑管家或者360老是提示不对.我就百度了在注册表里面改成了专业版的,接着继 ...

  6. 认识linux权限

    首先,我们来了解下linux系统的用户和用户组 场景:公司里有两个项目组:小组A和小组B:A.B.C是小组A的成员,甲.乙是小组B的成员.为了保密起见,小组内的进度.文档.程序都有小组内公开.比如小组 ...

  7. thinkphp 杂乱笔记(1)

    部署模式可用两个单入口表示前后台thinkphpUploadspublic Home(前台)Admin(后台)index.php(前台入口文件)admin.php(后台入口文件)上面两个项目目录 也可 ...

  8. rgba兼容IE系列

    在容器里面如果用到opacity或者filter:opacity里面的内容也会被滤镜化 如果不想里面的内容也被滤镜化我们可以用rgba来处理或者用透明的背景图片. 兼容ie的rgba的写法 backg ...

  9. 数据库MySQL与xls文件的互导

    最近的一个项目需要将xls表导入到MySQL数据库中和将MySQL数据表导出到xls表中,在网上搜了很多资料,经过多次尝试终于实现了功能,废话不多说,在这粘贴出代码,希望可以帮到需要的朋友. 一.将. ...

  10. 以中断方式实现1s定时

    中断方式比较特殊,需要使用单片机内部的中断处理机制,同时指定中断函数. #include <reg52.h> sbit LED = P0^; unsigned ; void main() ...