一、对比说明
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