本文共 11950 字,大约阅读时间需要 39 分钟。
public class MyThread extends Thread { private int count = 5; //synchronized public synchronized void run(){ count--; System.out.println(Thread.currentThread().getName()+" count="+count); } public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread1 = new Thread(myThread,"t1"); Thread thread2 = new Thread(myThread,"t2"); Thread thread3 = new Thread(myThread,"t3"); Thread thread4 = new Thread(myThread,"t4"); Thread thread5 = new Thread(myThread,"t5"); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); }}
public class MultiThread{ //加static private static int num = 0; //加static public static synchronized void print(String tag){ try{ if(tag.equals("a")){ num = 100; System.out.println("tag a set num over!"); Thread.sleep(3000); }else{ num = 200; System.out.println("tag b set num over!"); } System.out.println("tag" + " = " + tag + ",and num= " + num); } catch(InterruptedException e){ e.printStackTrace(); } } public static void main(String[] args) { final MultiThread m1 = new MultiThread(); final MultiThread m2 = new MultiThread(); Thread t1 = new Thread(new Runnable(){ @Override public void run() { //获得m1对象锁 m1.print("a"); } },"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { //获得m2对象锁 m2.print("b"); } },"t2"); t1.start(); t2.start(); }}/** * 加static之前(对象锁): * tag a set num over! * tag b set num over! * tag = b,and num= 200 * tag = a,and num= 100 * * 加static之后(类锁): * tag a set num over! * tag = a,and num= 100 * tag b set num over! * tag = b,and num= 200 * */
同步的目的就是为了线程安全,对于线程安全来说,需要满足两个特性:
public class MyObject { //synchronized public synchronized void method1() { try { System.out.println(Thread.currentThread().getName()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } //asynchronized public void method2(){ System.out.println(Thread.currentThread().getName()); } public static void main(String[] args) { MyObject obj = new MyObject(); Thread t1 = new Thread(new Runnable() { @Override public void run() { obj.method1(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { obj.method2(); } },"t2"); t1.start(); t2.start(); }}/** * 立即打印: * t1 * t2 * */
对于对象的同步和异步方法,我们在设计自己的程序时候,一定要考虑问题的整体性,不然就会出现数据的不一致的错误,很经典的就是脏读。
public class DirtyRead { String username = "zhangsan"; String password = "123"; public synchronized void setValue(String username,String password){ this.username = username; try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } this.password = password; System.out.println("setValue后的username= "+username+", password= "+password); } //synchronized public void getValue(){ System.out.println("getValue的username= "+username+", password= "+password); } public static void main(String[] args) throws InterruptedException { final DirtyRead dr = new DirtyRead(); Thread t1 = new Thread(new Runnable(){ @Override public void run() { dr.setValue("zhangsan", "456"); } }); t1.start(); Thread.sleep(1000); dr.getValue(); }}/** *打印结果: * getValue的username= zhangsan, password= 123 * setValue后的username= zhangsan, password= 456 * *想要的结果: *setValue后的username= zhangsan, password= 456 *setValue后的username= zhangsan, password= 456 * */
public class SyncDubbo { public synchronized void method1(){ System.out.println("method1..."); //锁重入 method2(); } public synchronized void method2(){ System.out.println("method2..."); //锁重入 method3(); } public synchronized void method3(){ System.out.println("method3..."); } public static void main(String[] args) { final SyncDubbo sd = new SyncDubbo(); Thread t1 = new Thread(new Runnable() { @Override public void run() { sd.method1(); } }); t1.start(); }}/**打印结果: * method1... * method2... * method3... * */
使用synchronized声明的方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个很长时间的任务,那么B线程就必须等待比较长的时间才能执行,这样的情况就可以使用synchronized代码块去优化代码执行时间,也就是缩小锁的粒度。
public class ObjectLock { public void method1(){ synchronized(this){//对象锁 try { System.out.println(Thread.currentThread().getName()+" method1..."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void method2(){ synchronized (ObjectLock.class) { try { System.out.println(Thread.currentThread().getName()+" method2..."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } private Object lock = new Object(); public void method3(){ synchronized (lock) { //任何对象锁 try { System.out.println(Thread.currentThread().getName()+" method3..."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final ObjectLock objectLock = new ObjectLock(); Thread t1 = new Thread(new Runnable(){ @Override public void run() { objectLock.method1(); } },"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { objectLock.method2(); } },"t2"); Thread t3 = new Thread(new Runnable(){ @Override public void run() { objectLock.method3(); } },"t3"); t1.start(); t2.start(); t3.start(); }}
public class StringLock { public void method(){ //new String("字符串常量") synchronized ("字符串常量") { try { while(true){ System.out.println(Thread.currentThread().getName()+"线程开始!"); Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+"线程结束!"); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final StringLock sl = new StringLock(); Thread t1 = new Thread(new Runnable(){ @Override public void run() { sl.method(); }},"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { sl.method(); }},"t2"); t1.start(); t2.start(); }}/** * 使用字符串常量时(一直给一个常量引用加锁):出现死循环 * t2线程开始! * t2线程结束! * t2线程开始! * t2线程结束! * t2线程开始! * t2线程结束! * t2线程开始! * t2线程结束! * t2线程开始! * * 使用new String()时: * t1线程开始! * t2线程开始! * t1线程结束! * t1线程开始! * t2线程结束! * t2线程开始! * t1线程结束! * t2线程结束! * t2线程开始! * t1线程开始! */
public class ChangeLock { private String lock = "lock"; public void method(){ synchronized (lock) { try{ System.out.println(Thread.currentThread().getName()+" start"); lock="change lock";//修改lock,对象本身发生改变,第二个线程持有不同对象锁 Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+" end"); }catch(InterruptedException e){ e.printStackTrace(); } } } public static void main(String[] args) { final ChangeLock cl = new ChangeLock(); Thread t1 = new Thread(new Runnable(){ @Override public void run() { cl.method(); }},"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { cl.method(); }},"t2"); t1.start(); t2.start(); }}
public class ModifyLock { private String username = "zhangsan"; private String password = "123"; public synchronized void modify(String username,String password){ try { this.username = username; //修改对象属性值,持有锁不变 System.out.println(Thread.currentThread().getName()+" start"); Thread.sleep(1000); this.password = password; //修改对象属性值,持有锁不变 System.out.println(Thread.currentThread().getName()+" end"); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { final ModifyLock modifyLock = new ModifyLock(); Thread t1 = new Thread(new Runnable(){ @Override public void run() { modifyLock.modify("lisi", "456"); }},"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { modifyLock.modify("wangwu", "789"); }},"t2"); t1.start(); t2.start(); }}/** * 打印结果: * t1 start * t1 end * t2 start * t2 end * */
public class RunThread extends Thread{ //volatile private volatile boolean isRunning = true; public void setRunning(boolean isRunning){ this.isRunning = isRunning; } public void run(){ System.out.println("进入run方法..."); while(isRunning == true){ // } System.out.println("线程停止..."); } public static void main(String[] args) throws InterruptedException { RunThread rt = new RunThread(); rt.start(); Thread.sleep(3000); rt.setRunning(false); System.out.println("isRunning的值被设置了false"); Thread.sleep(1000); System.out.println(rt.isRunning); }}/** * isRunning无volatile修饰时: * 进入run方法... * isRunning的值被设置了false * false *isRunning被volatile修饰时: * 进入run方法... * isRunning的值被设置了false * 线程停止... * false * */
一个线程可以执行的操作有使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock)。
而主内存可以执行的操作有读(read)、写(write)、锁定(lock)、解锁(unlock)。每个操作都是原子的。
volatile的作用就是强制线程到主内存(共享内存)里去读取变量,而不是去线程工作内存区里去读取,从而实现多个线程间的变量可见,也就是满足线程安全的可见性。
public class VolatileNotAtom extends Thread { //volatile //private static volatile int count; private static AtomicInteger count = new AtomicInteger(0); private static void addCount(){ for(int i = 0; i < 1000; i++){ //count++; count.incrementAndGet(); } System.out.println(count); } public void run(){ addCount(); } public static void main(String[] args) { VolatileNotAtom[] vna = new VolatileNotAtom[10]; for(int i = 0; i < 10; i++){ vna[i] = new VolatileNotAtom(); } for(int i = 0; i < 10; i++){ vna[i].start(); } }}/** * volatile不能实现原子性: * ... * 7679 * 8679 * 3679 * 9679 * * 使用AtomicInteger后: * ... * 6422 * 7000 * 8000 * 9000 * 10000 * */
public class AtomicUse { private static AtomicInteger count = new AtomicInteger(0); //synchronized public int multiAdd(){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } count.addAndGet(1); count.addAndGet(2); count.addAndGet(3); count.addAndGet(4); //作整十操作 return count.get(); } public static void main(String[] args) { final AtomicUse au = new AtomicUse(); Listts = new ArrayList<>(); for(int i = 0; i < 100; i++){ ts.add(new Thread(new Runnable(){ @Override public void run() { System.out.println(au.multiAdd()); } })); } for(Thread t : ts){ t.start(); } }}/** * 增加synchronized修饰时打印结果: * ... * 960 * 970 * 980 * 990 * 1000 * * 没有synchronized修饰时打印结果(出现了不是整十的数字13): * ... * 13 * 30 * 20 * 40 * 110 * */
转载地址:http://ybkni.baihongyu.com/