浅谈Java多线程的同步问题

来源:互联网 发布:淘宝网店代理商 编辑:程序博客网 时间:2024/06/06 21:52

学习Java的同学注意了!!! 
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:286945438 我们一起学Java!


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

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

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

复制代码
复制代码
package com.vista;

class MyThread implements java.lang.Runnable
{
    private int threadId;

    public MyThread(int id)
    {
        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块进行局部封锁,这样就可以让线程去竞争这个唯一的共享的对象锁,从而实现同步。

复制代码
代码
package com.vista;

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)
        {
            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);
        }
    }
}
复制代码

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

 

复制代码
代码
package com.vista;

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关键字封锁的就是类本身。静态方法是所有类实例对象所共享的,因此线程对象在访问此静态方法时是互斥访问的,从而可以实现线程的同步,代码如下所示:

复制代码
代码
package com.vista;

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的同学注意了!!! 
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:286945438 我们一起学Java!

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 流产后吹了风怎么办 怀孕1周内喝酒了怎么办 怀孕6周喝酒了怎么办 怀孕后喝了酒怎么办 不知道怀孕喝酒了怎么办 不知道怀孕了喝酒了怎么办 怀孕5天喝酒了怎么办 打孩子耳光后脸肿了怎么办 老师说上课不专心怎么办 孩子不专心好动马虎怎么办 学生上课不认真听讲怎么办 一年级孩子上课不注意听讲怎么办 一年级孩子上课说话不听课怎么办 一年级孩子上课不听课怎么办 小学一年级学生上课不专心怎么办? 小孩听课注意力不集中怎么办 小孩子上课精神不集中怎么办 孩子说我不画了怎么办 幼儿园小朋友上课不专心怎么办 孩子写作业不专心怎么办 小孩做作业不专心怎么办 孩子上课精力不集中怎么办 四岁宝宝吃饭慢怎么办 5岁宝宝吃饭慢怎么办 小学一年级上课不专心怎么办 5岁儿童不专心怎么办 小孩子做作业不专心怎么办 孩子做作业不专心怎么办 小孩学了就忘怎么办 小孩学过就忘了怎么办 做事老是注意力不集中怎么办 做事无法专注注意力不集中怎么办 幼儿园孩子上课不认真听讲怎么办 孩子在课间打闹家长应该怎么办 孩子打闹家长额钱怎么办 我又打孩子了怎么办 打排卵针不排卵怎么办 总是控制不住打骂孩子怎么办 叛逆期的孩子打骂妈妈怎么办 孩子屁股打青了怎么办 父亲把孩子屁股打流血怎么办