首页

关于线程同步使用synchronized和Lock对比及代码示例

标签:java,java基础,Lock,ReentrantLock,synchronized,用法,线程安全,并发控制,锁,demo     发布时间:2015-06-18   

一、对比说明

Synchronized:JVM级别的锁,是JVM的内置属性,可以重入,对于前言中的例子,我们可以加入Synchronized解决问题,如下所示

ReentrantLock:  JAVA类库级别的,功能更多:支持等待可中断,公平锁等等

需要获取更多相关知识,跳转到“Java并发编程基础知识分享

二、代码示例

1. synchronized用法

synchronized可以用户代码块、方法、静态方法、类加锁控制,具体用法如下所示

synchronized方法,针对同一对象,否则无法控制,示例代码如下:

package jh.modules.current;@b@@b@public class TestObjSynchronized {@b@    private  long pc=0;@b@    public   synchronized void print(){@b@        while(pc<10){@b@            pc++;@b@            if(pc%2==0)@b@                System.out.println(Thread.currentThread().getName()+"@pc:"+pc);@b@        }@b@    }@b@    /**@b@     * @param args@b@     */@b@    public static void main(String[] args) {@b@        // TODO Auto-generated method stub@b@        @b@        Runnable h1=new Runnable(){@b@            @Override@b@            public void run() {@b@                // TODO Auto-generated method stub@b@                TestObjSynchronized o=new TestObjSynchronized();@b@                o.print();@b@            }@b@            @b@        };@b@        @b@        Thread t1=new Thread(h1);@b@        Thread t2=new Thread(h1);@b@        t1.start();@b@        t2.start();@b@    }@b@}

运行结果,不能控制线程独占:

Thread-1@pc:2@b@Thread-0@pc:2@b@Thread-1@pc:4@b@Thread-0@pc:4@b@Thread-0@pc:6@b@Thread-1@pc:6@b@Thread-0@pc:8@b@Thread-1@pc:8@b@Thread-0@pc:10@b@Thread-1@pc:10

synchronized类可以实现,示例如下

public class TestObjSynchronized {@b@        private  long pc=0;@b@        public   void print(){@b@            synchronized(TestObjSynchronized.class){@b@                while(pc<10){@b@                    pc++;@b@                    if(pc%2==0)@b@                        System.out.println(Thread.currentThread().getName()+"@pc:"+pc);@b@                }@b@            }@b@        }@b@        public static void main(String[] args) {@b@            Runnable h1=new Runnable(){@b@                @Override@b@                public void run() {@b@                    TestObjSynchronized o=new TestObjSynchronized();@b@                    o.print();@b@                }@b@                @b@            };@b@            Thread t1=new Thread(h1);@b@            Thread t2=new Thread(h1);@b@            t1.start();@b@            t2.start();@b@        }@b@}

运行结果,可以实现线程控制

Thread-0@pc:2@b@Thread-0@pc:4@b@Thread-0@pc:6@b@Thread-0@pc:8@b@Thread-0@pc:10@b@Thread-1@pc:2@b@Thread-1@pc:4@b@Thread-1@pc:6@b@Thread-1@pc:8@b@Thread-1@pc:10

synchronized静态方法也可以,示例代码如下:

package jh.modules.current;@b@@b@public class TestSynchronized {@b@    private static long pc=0;@b@    public static synchronized void print(){@b@        while(pc<10){@b@            pc++;@b@            if(pc%2==0)@b@                System.out.println(Thread.currentThread().getName()+"@pc:"+pc);@b@        }@b@    }@b@    /**@b@     * @param args@b@     */@b@    public static void main(String[] args) {@b@        // TODO Auto-generated method stub@b@        @b@        Runnable h1=new Runnable(){@b@            @Override@b@            public void run() {@b@                // TODO Auto-generated method stub@b@                TestSynchronized.print();@b@            }@b@            @b@        };@b@        Thread t1=new Thread(h1);@b@        Thread t2=new Thread(h1);@b@        t1.start();@b@        t2.start();@b@    }@b@@b@}

运行结果如下:

Thread-0@pc:2@b@Thread-0@pc:4@b@Thread-0@pc:6@b@Thread-0@pc:8@b@Thread-0@pc:10

synchronized对象this和类组合对比,线程按顺序执行

package thread.lock;@b@@b@public class TestSynchronized {@b@	@b@	public void test1() {@b@		synchronized (this) {@b@			int i = 5;@b@			while (i-- > 0) {@b@				System.out@b@						.println(Thread.currentThread().getName() + " : " + i);@b@				try {@b@					Thread.sleep(500);@b@				} catch (InterruptedException ie) {@b@				}@b@			}@b@		}@b@	}@b@@b@	public synchronized void test2() {@b@		int i = 5;@b@		while (i-- > 0) {@b@			System.out.println(Thread.currentThread().getName() + " : " + i);@b@			try {@b@				Thread.sleep(500);@b@			} catch (InterruptedException ie) {@b@			}@b@		}@b@	}@b@@b@	public static void main(String[] args) {@b@		final TestSynchronized myt2 = new TestSynchronized();@b@		Thread test1 = new Thread(new Runnable() {@b@			public void run() {@b@				myt2.test1();@b@			}@b@		}, "test1");@b@		Thread test2 = new Thread(new Runnable() {@b@			public void run() {@b@				myt2.test2();@b@			}@b@		}, "test2");@b@		test1.start();  @b@		test2.start(); @b@		@b@	}@b@@b@}

控制台运行结果

test1 : 4@b@test1 : 3@b@test1 : 2@b@test1 : 1@b@test1 : 0@b@test2 : 4@b@test2 : 3@b@test2 : 2@b@test2 : 1@b@test2 : 0

2. Lock用法

使用Lock实现多对象都线程独占控制,示例如下:

package jh.modules.current;@b@@b@import java.util.concurrent.locks.Lock;@b@import java.util.concurrent.locks.ReentrantLock;@b@@b@public class TestLock {@b@    private static Lock lock=new ReentrantLock();@b@    private    long pc=0;@b@    public     void print(){@b@        lock.lock();@b@        while(pc<10){@b@            pc++;@b@            if(pc%2==0)@b@                System.out.println(Thread.currentThread().getName()+"@pc:"+pc);@b@        }@b@        lock.unlock();@b@    }@b@@b@    /**@b@     * @param args@b@     */@b@    public static void main(String[] args) {@b@        // TODO Auto-generated method stub@b@        Runnable h1=new Runnable(){@b@            @Override@b@            public void run() {@b@                // TODO Auto-generated method stub@b@                TestLock t=new TestLock();@b@                t.print();@b@            }@b@            @b@        };@b@        Thread t1=new Thread(h1);@b@        Thread t2=new Thread(h1);@b@        t1.start();@b@        t2.start();@b@    }@b@@b@}

运行结果如下:

Thread-0@pc:2@b@Thread-0@pc:4@b@Thread-0@pc:6@b@Thread-0@pc:8@b@Thread-0@pc:10@b@Thread-1@pc:2@b@Thread-1@pc:4@b@Thread-1@pc:6@b@Thread-1@pc:8@b@Thread-1@pc:10

 Lock一般会结合Condition使用,示例如下:

package thread.lock;@b@@b@import java.util.concurrent.locks.Condition;@b@import java.util.concurrent.locks.Lock;@b@import java.util.concurrent.locks.ReentrantLock;@b@ @b@/**@b@ *  类描述@b@ * @author nijun@b@ * @version v1.0 版本创建于  2015-6-19@b@ * @version v1.1更新于2021-09-04@b@ */@b@ @b@public class TestLock_Condition {@b@     @b@    static class NumberWrapper {@b@        public int value = 1;@b@    }@b@ @b@    public static void main(String[] args) {@b@         @b@        //初始化同步锁@b@        final Lock lock = new ReentrantLock();@b@         @b@        //条件输出1到3@b@        final Condition reach1_3Condition = lock.newCondition();@b@        //条件输出4到6@b@        final Condition reach4_6Condition = lock.newCondition();@b@         @b@        //NumberWrapper封装Integer不可变类,@b@        final NumberWrapper num = new NumberWrapper();@b@         @b@        //线程0(A) 用于输出1-3、7-9@b@        Thread threadA = new Thread(new Runnable() {@b@            @Override@b@            public void run() {@b@                //需要先获得锁@b@                lock.lock();@b@                try {@b@                    //1线程先输出前3个数@b@                    while (num.value <= 3) {@b@                        System.out.println(Thread.currentThread().getName()+":"+num.value);@b@                        num.value++;@b@                    }@b@                    //输出到3时要signal,通知线程2运行@b@                    reach1_3Condition.signal();@b@                } finally {@b@                    lock.unlock();@b@                }@b@                lock.lock();@b@                try {@b@                    //等待线程2返回@b@                    reach4_6Condition.await();@b@                    //输出剩余数字@b@                    while (num.value <= 9) {@b@                        System.out.println(Thread.currentThread().getName()+":"+num.value);@b@                        num.value++;@b@                    }@b@ @b@                } catch (InterruptedException e) {@b@                    e.printStackTrace();@b@                } finally {@b@                    lock.unlock();@b@                }@b@            }@b@ @b@        });@b@ @b@      //线程1(B) 用于输出4-6@b@        Thread threadB = new Thread(new Runnable() {@b@            @Override@b@            public void run() {@b@                try {@b@                    lock.lock();@b@                    while (num.value <= 3) {@b@                        //等待3输出完毕的信号@b@                        reach1_3Condition.await();@b@                    }@b@                } catch (InterruptedException e) {@b@                    e.printStackTrace();@b@                } finally {@b@                    lock.unlock();@b@                }@b@                try {@b@                    lock.lock();@b@                    //准备输出4,5,6@b@                    while (num.value <= 6) {@b@                        System.out.println(Thread.currentThread().getName()+"->"+num.value);@b@                        num.value++;@b@                    }@b@                    //4,5,6输出完毕,告诉A线程6输出完了@b@                    reach4_6Condition.signal();@b@                } finally {@b@                    lock.unlock();@b@                }@b@            }@b@ @b@        });@b@ @b@ @b@        //启动两个线程@b@        threadB.start();@b@         @b@        threadA.start();@b@         @b@    }@b@ @b@}

控制台结果

Thread-0:1@b@Thread-0:2@b@Thread-0:3@b@Thread-1->4@b@Thread-1->5@b@Thread-1->6@b@Thread-0:7@b@Thread-0:8@b@Thread-0:9