澳门皇冠金沙网站-澳门皇冠844网站

热门关键词: 澳门皇冠金沙网站,澳门皇冠844网站

皇冠手机网对象及变量的并发访问,第二章总结

线程安全,线程安全部都以怎么着看头

这几天求学并发编制程序,并发编制程序料定和二十四线程、线程安全有提到,那么上边是作者总计了团结攻读线程安全的笔记!!!

1.线程平安的概念

  三个线程访谈某二个类(对象或格局)时,那个类始终都能有限协助正确的行为,那么这些类(对象或措施是线程安全的)。

2.synchronized

  能够在随机对象和格局上加锁,而加锁的这段代码称为“互斥区”或“临界区”。

  a.示例

package com.wp.test;
public class MyThread extends Thread {
    private int count = 5;
    public synchronized void run(){
        count--;
        System.out.println(this.currentThread().getName() " count=" count);
    }
    public static void main(String args[]){
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"t1");
        Thread t2 = new Thread(myThread,"t2");
        Thread t3 = new Thread(myThread,"t3");
        Thread t4 = new Thread(myThread,"t4");
        Thread t5 = new Thread(myThread,"t5");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

  b.示例总括

  要是run方法前未有加关键字“synchronized”,那么对于多个线程操作count变量,是不安全的。加上“synchronized”时,那么线程是安枕无忧的;当八个线程访谈run方法时,以排队的格局开始展览管理(此处的排队是依照CPU分配的程序顺序而定),一个线程想要试行那一个synchronized修饰的run方法,首先要博取锁,借使获得不到,便会直接等到收获那把锁停止,此时,若是有多个线程,那么四个线程会竞争那把锁,那时会有锁竞争难题。锁竞争难点很导致应用程序比相当慢。

3.两个线程八个锁

  两个线程,各样线程都能够获得温馨钦赐的锁,分别赢得锁之后实施锁定的开始和结果。此处有五个概念:对象锁和类锁,示例总计将做解释。

  a.示例

皇冠手机网 1

package com.wp.test;
 /**
  * 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当作锁
  * 所以代码中哪个线程先执行synchronized对应的方法,该线程就持有该方法所属对象的锁(LOCK)
  * 
  * 在静态方法前加关键字synchronized,表示该方法的锁是类级别的锁。
 * 
 */
public class MultiThread {
    private  static int num = 0;
    /* static **/
    public static synchronized void printNum(String tag){
        try{
            if("a".equals(tag)){
                num = 100;
                System.out.println("tag a!set number over!");
                Thread.sleep(1000);
            }else{
                num = 200;
                System.out.println("tag b! set number over!");
            }
            System.out.println("num=" num);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    //注意观察run方法输出顺序
    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.printNum("a");
            }
        });
        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                m2.printNum("b");
            }
        });
        t1.start();
        t2.start();
    }
}

View Code

 

  实施结果:

1. 无static:
tag a!set number over!
tag b! set number over!
num=200
num=100
2.有static
tag a!set number over!
num=100
tag b! set number over!

  b.示例总计

  代码中线程猎取的锁都以指标锁,并不是把一段代码(或格局)当作锁,对象锁的性状是差异的目的对应着不同的锁,互不影响。在静态方法上助长关键字synchronized,表示锁定的是.class类,属于类级其余锁。

4.指标锁的一路和异步

  a.同步synchronized

  同步的概念是分享,要是多少个线程分享能源,那么就从不须要展开同步了。

  b.异步asynchronized

  异步的定义是独立,多少个线程彼此之间不受任何制约。

  c.同步的指标正是为着线程安全,对于线程安全,须求满足多少个特征:1).原子性(同步)    2).可知性

  d.示例

 

皇冠手机网 2

package com.wp.test;
 /**
 * 对象锁的同步和异步问题
 */
public class MyObject {
    public synchronized void method1(){
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public void method2(){
        System.out.println(Thread.currentThread().getName());
    }
    public static void main(String args[]){
        final MyObject mo = new MyObject();
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                mo.method1();
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                mo.method2();
            }
        },"t2");
        t1.start();
        t2.start();
    }
}

View Code

 

 

 

  示例总括:若t1线程先持有Object对象锁,t2线程借使这一年要调用对象中的同步(synchronized)方准则必要等待t1释放锁,本领够调用,也就说一道了;若t1线程先持有Object对象锁,t2线程那一年调用异步(非synchronized修饰)的措施,则会马上调用,t1和t2之间平素不影响,也就视为异步了。

 4.脏读

  对于目的的联手和异步方法,我们在设计的时候断定要牵记难点的全部性,不然就能够产出数量不等同的荒谬,很非凡的一个谬误就是脏读。

  a.示例

皇冠手机网 3

package com.wp.test;
public class DirtyRead {
    private String uname = "sxt";
    private String pwd = "123";
    public synchronized void setValue(String uname,String pwd){
        try {
            this.uname = uname;
            Thread.sleep(2000);
            this.pwd = pwd;
            System.out.println("setValue设置的值:uname=" uname " pwd=" pwd);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public void getValue(){
        System.out.println("getValue的最终值:uname=" uname " pwd=" pwd);
    }
    public static void main(String args[]) throws Exception{
        final DirtyRead dr = new DirtyRead();
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                dr.setValue("wangping", "456");
            }
        });
        t.start();
        Thread.sleep(1000);
        dr.getValue();
    }
}
/**getValue的最终值:uname=wangping pwd=123

  setValue设置的值:uname=wangping pwd=456*/

View Code

 

  b.示例深入分析

  pwd不同,消除方式:getValue方法加关键字synchronized。加上对象锁之后,等到锁被放走才得以获取锁。保持业务数据一致性。

  c.示例计算

  当我在给目的的方法加锁的时候,必须要考虑工作的全体性,即示例中setValue和getValue方法都加synchronized锁住,就确认保障了政工的原子性,保障专门的学业不会出错。

  d.oracle关系型数据库,一致性读完成原理

  案例描述:oracle,用户A,9点查询某条数据(100),9:10技巧够查到所需数据。而用户B在9:05施行了DML操作,那么A所查的数量在数据库已经转移(200)。那么A在9:10查到的结果是100照旧200?答案是:100。

      原因:oracle数据库有一致性读的特色。B在update时,会将事先的多郎中存到undo中做笔录。当A在9:00这一每一日查时,将这一动作保存到ITL中,当A在9:10查100数额时,会剖断ITL中对该数量的动作是或不是更新(是不是在9:00这一刻之后产生变化),若是更新了,那么会从100对应的undo军长在此以前的数额重返。所以,结果为100。

  Undo的功效:提供一致性读(Consistent Read)、回滚事务(Rollback Transaction)以及实例苏醒(Instance Recovery)。

  详细表明:

5.synchronized锁重入

  关键字synchronized具有锁重入的效果,约等于在应用synchronized时,当多个对象得到指标锁之后,不释放锁,还足以另行赢得该目的的锁,称为锁重入。

  a.示例1:方法锁重入

皇冠手机网 4

package com.wp.test;
public class SyncDubbo1 {
    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 SyncDubbo1 s = new SyncDubbo1();
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                s.method1();
            }
        });
        t.start();
    }
}
/**结果:

 * method1-----------------

 * method2------------------

* method3------------------
*/

View Code

 

  示例2:子类方法锁重入

皇冠手机网 5

package com.wp.test;
public class SyncDubbo2 {
    static class Main{
        public int i = 10;
        public synchronized void operationSup(){
            try{
                i--;
                System.out.println("Main print i=" i);
                Thread.sleep(100);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    static class Sub extends Main{
        public synchronized void operationSub(){
            try{
                while(i>0){
                    i--;
                    System.out.println("Sub print i=" i);
                    Thread.sleep(100);
                    this.operationSup();
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    public static void main(String args[]){
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                Sub s = new Sub();
                s.operationSub();
            }
        });
        t.start();
    }
}

View Code

 

  结果:

Sub print i=9
Main print i=8
Sub print i=7
Main print i=6
Sub print i=5
Main print i=4
Sub print i=3
Main print i=2
Sub print i=1
Main print i=0

  示例3:锁中的内容出现分外

  对于web应用程序,至极释放锁的事态,若是不特殊管理,那么业务逻辑晤面世很要紧的错,比如施行贰个体系职务,很对职分目的都在等候第三个目的不错实行完之后释放锁,然而执行第五个指标时出现了老大,导致剩余任务未有实施,那么业务逻辑就能够产出严重错误,所以在设计代码的时候绝对要严谨思考。

  解决措施:出现分外时,捕获格外后通过记录特别消息到日志文件,然后剩余职分目的继续施行,那么任何任务实行完事后,再对出现非凡的足够职务指标举行拍卖,进而不会影响别的职分目的的施行。

皇冠手机网 6

package com.wp.test;
public class SyncException {
    private int i = 0;
    public synchronized void operation(){
        while(true){
            try{
                i  ;
                Thread.sleep(200);
                System.out.println(Thread.currentThread().getName() ",i=" i);
                if(i==3){
                    Integer.parseInt("a");//throw RuntimeException
                }
            }catch(Exception e){
                e.printStackTrace();
                System.out.println("log info i=" i);
            }
        }
    }
    public static void main(String args[]){
        final SyncException se = new SyncException();
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
               se.operation();
            }
        });
        t.start();
    }
}

View Code

 

  结果:推行措施的时候,出现万分,不会释放锁,业务继续实施。推行完事后,对爆发的十三分进行管理。比方说仓库储存过程:当更新某张表的多少时,出现至极,那么将不胜音信保存到日志表中,稍后举行拍卖,而使得该表的数据继续立异。

Thread-0,i=1
Thread-0,i=2
Thread-0,i=3
java.lang.NumberFormatException: For input string: "a"
log info i=3
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at com.wp.test.SyncException.operation(SyncException.java:11)
    at com.wp.test.SyncException$1.run(SyncException.java:24)
    at java.lang.Thread.run(Thread.java:745)
Thread-0,i=4
Thread-0,i=5
Thread-0,i=6

6.synchronized关键字

  使用synchronized注脚的不二法门在好几情形下是有坏处的,比方A线程调用同步的方法实施叁个非常短日子的天职,那么B线程就非得等待一样长的时日技术实行,那样的情事下能够利用synchronized代码块去优化代码奉行时间,常常说,减小了锁的粒度。

  Synchronized能够选拔狂妄的Object进行加锁,用法相比灵活。

  极其注意,就是永不使用String的常量加锁,会出现死循环难题。

  锁对象更动难题:当使用一个目标实行加锁的时候,要注意对象自己是不是发生变化(地址),如若发生变化,那么就可以放出锁。例如,要是是字符串的锁,当字符串改造后就能够自由锁。可是,对象的属性发生变化,不会有影响的。

  a.示例1:synchronized代码块

皇冠手机网 7

package com.wp.test;
public class ObjectLock {
    public void method1(){
        synchronized(this){
            try {
                System.out.println("do method1...");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void method2(){
        synchronized(ObjectLock.class){
            try {
                System.out.println("do method2...");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private Object lock = new Object();
    public void method3(){
        synchronized(lock){
            try {
                System.out.println("do method3...");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String args[]){
        final ObjectLock ol = new ObjectLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                ol.method1();
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                ol.method2();
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                ol.method3();
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

View Code

 

  结果:

do method1...
do method3...
do method2...

  b.示例2:字符串锁改造

皇冠手机网 8

package com.wp.test;
public class ChangeLock {
    private String lock = "lock";
    public void method(){
        synchronized(lock){
            try {

                System.out.println("当前线程:" Thread.currentThread().getName() "开始");
                lock = "lock1";
                Thread.sleep(2000);
                System.out.println("当前线程: " Thread.currentThread().getName() "结束");
            } 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();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }

View Code

 

  结果:字符串改动以后,会放出锁。

  示例3:

皇冠手机网 9

package com.wp.test;
public class ModifyLock {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public synchronized void changeAttribute(String name,int age){
        try {
            System.out.println("当前线程:" Thread.currentThread().getName() "开始");
            this.setName(name);
            this.setAge(age);
            System.out.println("当前线程:" Thread.currentThread().getName() "修改的内容为:"
                     this.getName() "," this.getAge());
            Thread.sleep(2000);
            System.out.println("当前线程:" Thread.currentThread().getName() "结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String args[]){
        final ModifyLock ml = new ModifyLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                ml.changeAttribute("张三", 20);
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
               ml.changeAttribute("李四", 21);
            }
        },"t2");
        t1.start();
        t2.start();
    }
}

View Code

 

  结果分析:假若指标自己不产生变化,那么依旧同步,属性别变化化,未有影响,依旧同步。

7.volatile关键字

  当三个线程使用同一变量时,为了线程安全,平常大家会在访谈变量的地点加一把锁,可是这么作用极低。可是Volatile的频率相对高点。

  Volatile关键字的关键意义是使用变量在多少个线程间可知。原理:强制线程到主内部存款和储蓄器里去读取变量,而不去线程事行业内部部存款和储蓄器区去读,那么当前线程使用的变量是风尚的变量(不管其余线程有无修改),进而完结了三个线程间变量可知,相当于知足了线程安全的可知性。若是不知晓,下边包车型客车亲自过问,运转一下,就清楚了。

皇冠手机网 10

package com.wp.test;
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);
    }
}

View Code

 

  结果深入分析:isRunning不用volatile修饰时,当主线程修改isRunning的值时,线程rt的内部存款和储蓄器中的isRunning副本不会生成;isRunning用volatile修饰时,当主线程修改isRunning的值时,会强制线程rt从内部存款和储蓄器中读取isRunning的值,那么rt内部存款和储蓄器里的isRunning也就爆发了修改。

 

  Volatile关键字即使有所三个线程之间的可知性,不过却不享有同步性(相当于原子性),能够算得上二个轻量级的synchronized,品质要比synchronized强非常多,不会导致堵塞(在不少开源的框架里,比方netty的底层代码正是多量应用volatile,可知netty品质特别正确。)这里须求专注,一般volatile用于只针对于多少个线程可知的变量操作,并不能庖代synchronized的一道作用。具体来说,volatile关键字独有可知性,未有原子性。要促成原子性,建议接纳atomic类的多元对象,扶助原子性操作(注意atomic类只保障自个儿方法原子性,并不有限扶助数次操作的原子性)。用三个演示说明:

  示例1:volatile关键字唯有可知性,未有原子性,建议使用atomic类的文山会海对象

皇冠手机网 11

package com.wp.test;
import java.util.concurrent.atomic.AtomicInteger;
public class VolatileNoAtomic extends Thread {
    //private static volatile int count;
    private static AtomicInteger count = new AtomicInteger();
    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[]){
        VolatileNoAtomic[] arr = new VolatileNoAtomic[10];
        for(int i=0;i<10;i  ){
            arr[i] = new VolatileNoAtomic();
        }
        for(int i=0;i<10;i  ){
            arr[i].start();
        }
    }
}

View Code

  结果分析:当使用volatile修饰时,由于并未有原子性,因此,(线程不安全)结果达不到一千0;那么使用AtomicInteger时,具备原子性,结果准确为10000。

  示例2:atomic类只保障自个儿方法原子性,并不有限支撑多次操作的原子性

皇冠手机网 12

package com.wp.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicUse {
    private static AtomicInteger count = new AtomicInteger(0);
    //多个addAndGet在一个方法内是原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
    /**synchronized*/
    public synchronized 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();
        List<Thread> ts = new ArrayList<Thread>();
        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();
        }
    }
}

View Code

  结果剖判:五个addAndGet在一个格局内是原子性的,须求加synchronized实行修饰,保险4个addAndGet全体原子性。不加,每回加的值不是整10,加的话是整10。

近些日子上学并发编制程序,并发编程料定和多线程、线程安全有涉嫌,那么下边是自己总括了上下一心上学线程安全的笔...

2.16锁对象的改换

public class Service {
    private String lock = "123";
     public   void testMethod( ){ 
         synchronized (lock) { 
                System.out.println(Thread.currentThread().getName() " begin");
                lock  = "456";
                System.out.println(" lock changed ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) { 
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() " end");
        }
     } 
}



public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod();
       }
}

public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod();
       }
}

public class Run { 
    public static void main(String[] args) throws InterruptedException { 
        Service service = new Service();
        ThreadA threada = new ThreadA(service);
        ThreadB threadb = new ThreadB(service);
        threada.setName("a");
        threadb.setName("b");
        threada.start();
//      Thread.sleep(500);
        threadb.start();
    } 
} 


运行结果Thread.sleep(500);注释与不注释
注释的话,lock,a线程先运行lock兑现发生改变,虽然a没有释放锁,但是b获取的锁 和a获取的锁不一样,b也可以执行
a begin
 lock changed 
b begin
 lock changed 
a end
b end

不注释的话,a b同时执行,争抢"123"这个锁,只有当先执行完成的释放锁之后,后执行的才开始
a begin
 lock changed 
a end
b begin
 lock changed 
b end

设若对象不改变,尽管是目的的习性发生变化,如故是一块效果

public class UserInfo {
    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    } 
}



public class Service { 
     public   void testMethod( UserInfo userinfo){ 
         synchronized (userinfo) { 
                System.out.println(Thread.currentThread().getName() " begin");
                userinfo.setUsername("abcabcabc");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) { 
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() " end");
        }
     } 
}


public class ThreadA extends Thread {
    private Service service;
    private UserInfo info;
    public ThreadA(Service service,UserInfo info){
        this.service = service;
        this.info = info;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod(info);
       }
}

public class ThreadB extends Thread {
    private Service service;
    private UserInfo info;
    public ThreadB(Service service,UserInfo info){
        this.service = service;
        this.info = info;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod(info);
       }
}

public class Run { 
    public static void main(String[] args) throws InterruptedException { 
        Service service = new Service();
        UserInfo info = new UserInfo();
        ThreadA threada = new ThreadA(service,info);
        ThreadB threadb = new ThreadB(service,info);
        threada.setName("a");
        threadb.setName("b");
        threada.start();
        Thread.sleep(500);
        threadb.start();
    } 
} 

运行结果:
虽然a先运行,所对象的属性发生了改变,但是对象并没有改变,还是同步

2.12八线程的死锁

  死锁是一个经文的三十二线程难题,因为不相同的线程都在伺机根本不容许释放的锁(),进而致使全体的职责都力不能及进展。在二十四线程本领中死锁是必须防止的,因为那会促成线程的“假死”。

  死锁是程序设计的bug,在计划程序的进程中要防止出现互周旋有对方锁的情况。

  死锁出现的大旨:存在相互等待对方释放锁就有希望出现死锁。


2.10数据类型String的常量池本性

public class Service {
     public   void printA(String param){ 
         synchronized (param) {
            while(true){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) { 
                    e.printStackTrace();
                }
            }
        }
     } 
}


public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.printA("AA");
       }
}

public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.printA("BB");
       }
}

public class Run { 
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA ta = new ThreadA(service);
        ThreadB tb = new ThreadB(service);

        ta.setName("a");
        tb.setName("b");

        ta.start();
        tb.start(); 
    } 
}
运行结果:a b随机打印

public class Service {
     public   void printA(String param){ 
         synchronized (param) {
            while(true){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) { 
                    e.printStackTrace();
                }
            }
        }
     } 
}


public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.printA("AA");
       }
}

public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.printA("AA");
       }
}

public class Run { 
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA ta = new ThreadA(service);
        ThreadB tb = new ThreadB(service);

        ta.setName("a");
        tb.setName("b");

        ta.start();
        tb.start(); 
    } 
}
运行结果:两个线程使用了同一个锁对象"AA",a线程持有锁之后,一直运行,没有释放锁,b线程一直等待

3.7synchronized代码块有volatile同步的效用

  synchronized不仅独有使四个线程访谈统一资源时顺序同步的效果,他也得以将线程的个人内部存款和储蓄器变量与公私内部存款和储蓄器变量同步的效应。

 

  注:synchronized可以确认保障在同样时刻,唯有一个线程能够实行某一个主意或某贰个代码块,它包含五个特色:互斥性与可知性。

  synchronized不独有能够消除二个线程看到目的处于不平等的景况(这里说的是可知性,指的是说能够确认保障对象在线程内部存款和储蓄器与国有内部存款和储蓄器保持一致。)

  还足以确定保障步向同步方法或联名代码块的每二个线程,都能看出由同一个锁爱抚在此之前全部的退换效果(这里说的正是互斥性了,能够看到在谐和开始展览加锁前(前提是当下线程抢到实行权),上二个线程锁在其锁中间完结的百分百操作)。

  学习八线程八个大字:“外练互斥、内修可知”。

 

  看到这里是否有一些傻眼。。。好几小节的东西最佳蓦然告诉你,其实你以往在行使的就是相持最佳的。

  基础的学习正是这么,一步一步才干踏实,然后才可以有友好的东西。唯有看到不佳的位置,才会想要做到越来越好的地点。

  枯燥吗?幸好,只是长日子高强度的话,脑袋却是有一点点懵,然后呢?还不错吧,越大越开采学习的吸引力,不得不说稍微伤感。

  以温馨的曲折为鉴吧。

 

  小编的博客将在搬运一只至Tencent云 社区,邀约我们一起入驻:

 

  新浪也会同步举行维护。

 


 

2.3synchronized代码块间的同步性

public class ObjectService {

    public void serviceMethodA() {
        try {
            synchronized (this) {
                System.out.println("A begin time="   System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("A end    end="   System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void serviceMethodB() {
        synchronized (this) {
            System.out.println("B begin time="   System.currentTimeMillis());
            System.out.println("B end    end="   System.currentTimeMillis());
        }
    }
}

public class ThreadA extends Thread {

    private ObjectService service;

    public ThreadA(ObjectService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.serviceMethodA();
    } 
}

public class ThreadB extends Thread {
    private ObjectService service;

    public ThreadB(ObjectService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.serviceMethodB();
    }
}

public class Run {

    public static void main(String[] args) {
        ObjectService service = new ObjectService();

        ThreadA a = new ThreadA(service);
        a.setName("a");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("b");
        b.start();
    }

}
运行结果:两个同步代码块按顺序执行
同步的锁都是this
A begin time=1472655529707
A end    end=1472655531707
B begin time=1472655531707
B end    end=1472655531707

2.13内置类与静态内置类

  就是写了内部类跟静态内部类怎么开创。


1.1措施中的变量呈线程安全景况

方法中的变量不设无线程安全难点,永恒是线程安全的,那是艺术内部的变量是个体的表征决定的

public class HasselePrivateNum {
    public void add(String username){
        try{
            int num = 0;
            if(username.equals("a")){
                num = 100;
                System.out.println("a set num");
                Thread.sleep(2000);
            }else{
                num = 200;
                System.out.println("b set num");
            }
            System.out.println("username= " username "  num=" num);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class ThreadA extends Thread{ 
    private HasselePrivateNum numRef;
    public ThreadA(HasselePrivateNum numRef){
        super();
        this.numRef = numRef;
    }
     @Override
    public void run() { 
         super.run();
         numRef.add("a");
    } 
}

public class ThreadB extends Thread { 
    private HasselePrivateNum numRef;
    public ThreadB(HasselePrivateNum numRef){
        super();
        this.numRef = numRef;
    }
     @Override
    public void run() { 
         super.run();
         numRef.add("b");
    } 
}

public class Run { 
    public static void main(String[] args) { 
        HasselePrivateNum numRef = new HasselePrivateNum();
        ThreadA threadA = new ThreadA(numRef);
        ThreadB threadB = new ThreadB(numRef);
        threadA.start();
        threadB.start();
    } 
}
运行结果:
a set num
b set num
username= b  num=200
username= a  num=100

1.7出现分外锁自动释放

  当多个线程实施的代码出现非凡时,其所持有的锁会自动释放,锁被放飞后,别的排队等待的线程就能够赢稳妥前的对象锁。


 

1.7出现非常,锁自动释放

线程a现身十分,释放锁,线程b实践

public class Service { 
    synchronized public void testMethod(){
        if(Thread.currentThread().getName().equals("A")){
            System.out.println("before exception");
            Integer.parseInt("a");
            System.out.println("Thread A run");
        }else{
            System.out.println("Thread B run ");
        }
    } 
}

public class ThreadA extends Thread{ 
    private Service service;
    public ThreadA(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod();
    }
}

public class ThreadB extends Thread { 
    private Service service;
    public ThreadB(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod();
    }
}

public class Run { 
    public static void main(String[] args) { 
         Service service = new Service();
         ThreadA threada = new ThreadA(service);
         threada.setName("A");
         threada.start(); 

         ThreadB threadb = new ThreadB(service);
         threadb.setName("B");
         threadb.start(); 
    } 
}


运行结果
before exception
Thread B run 
Exception in thread "A" java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at t1.Service.testMethod(Service.java:7)
    at t1.ThreadA.run(ThreadA.java:12)

2.2synchronized联袂代码块的采取

  八个线程同一时候做客同三个指标的synchronized(this)同步代码块时,在代码运维时期只好有多少个线程实践该段代码块,另多少个线程必须等待眼下线程实现实行展能力能够施行该段代码。

  使用方面那句话完毕的例子带来的效用也并未有增加,原因在于同步代码块中依旧带有了具备的代码,包罗线程安全和非线程安全的代码。


1.2实例变量非线程安全

假定八个目的同一时间做客一个目的的实例变量,则有希望出现非线程安全主题素材

public class HasselePrivateNum {
    private int num = 0;
    public void add(String username){
        try{ 
            if(username.equals("a")){
                num = 100;
                System.out.println("a set num");
                Thread.sleep(2000);
            }else{
                num = 200;
                System.out.println("b set num");
            }
            System.out.println("username= " username "  num=" num);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class ThreadA extends Thread{ 
    private HasselePrivateNum numRef;
    public ThreadA(HasselePrivateNum numRef){
        super();
        this.numRef = numRef;
    }
     @Override
    public void run() { 
         super.run();
         numRef.add("a");
    } 
}

public class ThreadB extends Thread { 
    private HasselePrivateNum numRef;
    public ThreadB(HasselePrivateNum numRef){
        super();
        this.numRef = numRef;
    }
     @Override
    public void run() { 
         super.run();
         numRef.add("b");
    } 
}

public class Run { 
    public static void main(String[] args) { 
        HasselePrivateNum numRef = new HasselePrivateNum();
        ThreadA threadA = new ThreadA(numRef);
        ThreadB threadB = new ThreadB(numRef);
        threadA.start();
        threadB.start();
    } 
}
运行结果:
a set num
b set num
username= b  num=200
username= a  num=200 

一齐管理

public class HasselePrivateNum {
    private int num = 0;
    public synchronized void add(String username){
        try{ 
            if(username.equals("a")){
                num = 100;
                System.out.println("a set num");
                Thread.sleep(2000);
            }else{
                num = 200;
                System.out.println("b set num");
            }
            System.out.println("username= " username "  num=" num);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
运行结果:
a set num
username= a  num=100
b set num
username= b  num=200

2.10数据类型String的常量池个性

  由于String具有常量池缓存的作用,将synchronized(String)同步代码块与String联合起来使用时,要注意常量池带来的震慑。

  若有String A = String B = “同样的字符串”; 则synchronized(A)与synchronized(B)就有着一把同样的锁,就有望出现堵塞的光景。


 

1.6synchronized锁重入

当一个线程获得一个指标锁后,再度央求此目的锁时是可以再一次得到到该目的的锁的
也正是synchronized内部调用本类的别的synchronized方法时,长久是足以获得锁的

public class Service {
    synchronized public void service1(){
        System.out.println("service1");
        service2();
    }

    synchronized public void service2(){
        System.out.println("service2");
        service3();
    }

    synchronized public void service3(){
        System.out.println("service3");
    }
}


public class MyThread extends Thread { 
    @Override
    public void run() { 
        Service service = new Service();
        service.service1();
    } 
}

public class Run { 
    public static void main(String[] args) { 
        MyThread thread = new MyThread();
        thread.start();
    } 
}

3.2消除协同死循环


 

1synchronized联合方法

2.9静态同步synchronized方法与synchronized(class)代码块

  关键字synchronized还足以采取在static静态方法上,固然这么写,那是对脚下的*.java文件对应的Class类实行加锁。

  注:synchronized关键字修饰static静态方法是给Class类加锁,而synchronized关键字加到非static静态方法上是给目的上锁。

  Class锁能够对类的之所以目的实例起效能,使其代码的实行是三头的(不过注意假若有代码块锁的是Class的实例对象,则是分裂的锁,是指标锁,此时的代码与Class锁的代码实践是异步的)。

  synchronized(class)代码块的机能与synchronized static方法的机能是一样的。

  这一节其实正如难知晓,不过假如你能够清楚锁的指标之间的区别只怕就能够更加好的明亮为啥一同为什么异步。


 

2.8.2当别的线程施行x对象的sychronized同步方法呈同步效果

public class MyObject {
    synchronized public void printStr(){
        System.out.println(Thread.currentThread().getName()   "printStr getLock");
        System.out.println("--------------");
        System.out.println(Thread.currentThread().getName() "printStr releaseLock");
    }
}

public class MyService {
    public void testMethod1(MyObject obj){
        synchronized (obj) {
            try {
                System.out.println(Thread.currentThread().getName() " testMethod1  getLock");
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() " testMethod1 releaseLock");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadA extends Thread {
    private MyService ser;
    private MyObject obj;
    public ThreadA(MyService ser,MyObject obj){
        super();
        this.ser = ser;
        this.obj = obj;
    }
    @Override
    public void run() {
        super.run();
        ser.testMethod1(obj);
    }
}

public class ThreadB extends Thread {

    private MyService ser;
    private MyObject obj;
    public ThreadB(MyService ser,MyObject obj){
        super();
        this.ser = ser;
        this.obj = obj;
    }
    @Override
    public void run() {
        super.run();
        obj.printStr();
    } 
}

public class Run { 
    public static void main(String[] args)     { 
        MyObject obj = new MyObject();
        MyService ser = new MyService();
        ThreadA ta = new ThreadA(ser,obj);
        ta.setName("a");
        ThreadB tb = new ThreadB(ser,obj);
        tb.setName("b");
        ta.start();
        tb.start();
    } 
}
运行结果:testMethod1锁的是MyObject对象,printStr方法也是锁MyObject对象,而且是同一个对象的锁所以在第一个执行完成释放锁之后才会执行下一个
a testMethod1  getLock
a testMethod1 releaseLock
bprintStr getLock
--------------
bprintStr releaseLock

2.3用协同代码块消除协同方法的害处

  当四个线程访问object中的synchronized同步代码块时,其余线程能够访问该object对象中国和北美洲synchronized(this)同步代码块的内容。

  分部方那句话对同步代码块的优化方案便是,将线程安全且耗费时间的代码放在一块儿代码块外面,将非线程安全的代码放在一同代码快中,利用八线程的“同不经常间性”(并发性)达成缩长时间升高功能,且维持这几天目的具有锁,幸免非线程安全的标题出现。


 

2.13里边类与静态内部类

public class OutObject {

    static class InnerObj1{
        //使用的锁是InnerObj2的实例对象
        public void method1(InnerObj2 obj2){
            String threadName = Thread.currentThread().getName(); 
            synchronized (obj2) {
                System.out.println(threadName "进入InnerObj1 的 method1");
                for(int k=0;k<5;k  ){
                    System.out.println("k=" k);
                    try {
                        Thread.sleep(600);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(threadName "离开InnerObj1 的 method1");
            }
        }
        //使用的锁是InnerObj1的实例对象
        public synchronized void method2(){ 
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName "进入InnerObj1 的 method2");
            for(int k=0;k<5;k  ){
                System.out.println("k=" k);
                try {
                    Thread.sleep(600);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(threadName "离开InnerObj1 的 method2"); 
        } 
    }

    static class InnerObj2{
        //使用的对象时InnerObj2的实例对象
        public synchronized void method1(){
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName "进入InnerObj2 的 method1");
            for(int k=0;k<5;k  ){
                System.out.println("k=" k);
                try {
                    Thread.sleep(600);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(threadName "离开InnerObj2 的 method1");
        }
    }
}


public class Run { 
    public static void main(String[] args) { 

        final InnerObj1  inObj1 = new InnerObj1();
        final InnerObj2  inObj2 = new InnerObj2();
        Thread t1 = new Thread(new Runnable(){ 
            @Override
            public void run() {
                inObj1.method1(inObj2);//1.传的是inObj2
            } 
        },"T1");

        Thread t2 = new Thread(new Runnable(){ 
            @Override
            public void run() {
                inObj1.method2( ); 
            } 
        },"T2");

        Thread t3 = new Thread(new Runnable(){ 
            @Override
            public void run() {
                inObj2.method1( ); //2.inObj2调用的方法
            } 
        },"T3");

        t1.start();
        t2.start();
        t3.start();

    } 
}
//T3  T1用的是同一个锁,innObj2对象所以是同步进行
//t2的所对象是另一个,所以跟其他两个线程异步

2.8细化论证3个结论  

多个结论:

  •   当三个线程同一时间实行synchronized(x){}同步代码块时呈同步效果
  •   当其余线程实施x对象中的synchronized同步方法时呈同步效果
  •   当别的线程推行x对象中的synchronized(this)方法时也呈现同步效果

  注:能够这么明白,因为synchronized(x)中,对象监视器是x,便是将锁加载了x上,那么对于x对象来讲,他本人已经被上锁,则他的synchronized方法与synchronized(this)自然与synchronized(x){}呈同步效果。


1.5脏读

脏读是指在读取实例变量的时候,这些值已经被另外线程改变过了,也正是例外线程争抢实例变量的结果

public class PublicVar {
    public String username = "A";
    public String password = "AA";

    synchronized public void setValue(String username,String password){
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setvalue method thread name" Thread.currentThread().getName());
            System.out.println(username  "  " password);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
     public  void getValue(){
        System.out.println("getvalue method thread name" Thread.currentThread().getName());
        System.out.println(username  "  " password);
    } 
}

public class ThreadA extends Thread{ 
    private PublicVar pv;
    public ThreadA(PublicVar pv){
        super();
        this.pv = pv;
    }
    @Override
    public void run() {
        super.run();
        pv.setValue("B", "BB");
    }
}

public class Run { 
    public static void main(String[] args) { 
         try {
            PublicVar pv = new PublicVar();
             ThreadA thread = new ThreadA(pv);
             thread.start();
             Thread.sleep(200);
             pv.getValue();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } 
}
运行结果:
getvalue method thread namemain
B  AA
setvalue method thread nameThread-0
B  BB

public class PublicVar {
    public String username = "A";
    public String password = "AA";

    synchronized public void setValue(String username,String password){
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setvalue method thread name" Thread.currentThread().getName());
            System.out.println(username  "  " password);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public  void getValue(){
        System.out.println("getvalue method thread name" Thread.currentThread().getName());
        System.out.println(username  "  " password);
    } 
}

运行结果:
setvalue method thread nameThread-0
B  BB
getvalue method thread namemain
B  BB

2.5synchronized代码块间的同步性

  若五个线程访问了object的多个synchronized(this)同步代码块时,其余线程对同贰个object中具备的另外synchronized(this)同步代码块的寻访将被卡住。

  这么些情形声明了:synchronized使用的是一个指标监视器(此处用的是this)。

  随即产生了盲人摸象:synchronized(this)/synchronized(非this对象)与协助进行方法是还是不是同步,于是做了测量试验。

  synchronized(this)与当下目的的共同方法是共同的,两个公用一把指标锁。

  synchronized(非this对象)与如今指标的一块儿方法是异步的,两个不共用一把指标锁。


2.5一半同步一半不一同

public class Task { 
    public void doLongTimeTask() {
        for (int i = 0; i < 10 ; i  ) {
            System.out.println("nosynchronized threadName="
                      Thread.currentThread().getName()   " i="   (i   1));
        }
        System.out.println("");
        synchronized (this) {
            for (int i = 0; i < 10 ; i  ) {
                System.out.println("synchronized threadName="
                          Thread.currentThread().getName()   " i="   (i   1));
            }
        } 
    }
}

public class MyThread1 extends Thread { 
    private Task task; 
    public MyThread1(Task task) {
        super();
        this.task = task;
    } 
    @Override
    public void run() {
        super.run();
        task.doLongTimeTask();
    } 
}

public class MyThread2 extends Thread { 
    private Task task; 
    public MyThread2(Task task) {
        super();
        this.task = task;
    } 
    @Override
    public void run() {
        super.run();
        task.doLongTimeTask();
    } 
}

public class Run { 
    public static void main(String[] args) {
        Task task = new Task(); 
        MyThread1 thread1 = new MyThread1(task);
        thread1.start(); 
        MyThread2 thread2 = new MyThread2(task);
        thread2.start();
    }
}



运行结果:非同步的交叉打印,同步的排队打印
nosynchronized threadName=Thread-0 i=1
nosynchronized threadName=Thread-0 i=2
nosynchronized threadName=Thread-1 i=1
nosynchronized threadName=Thread-1 i=2
nosynchronized threadName=Thread-1 i=3
nosynchronized threadName=Thread-1 i=4
nosynchronized threadName=Thread-1 i=5
nosynchronized threadName=Thread-1 i=6
nosynchronized threadName=Thread-1 i=7
nosynchronized threadName=Thread-1 i=8
nosynchronized threadName=Thread-1 i=9
nosynchronized threadName=Thread-1 i=10

synchronized threadName=Thread-1 i=1
synchronized threadName=Thread-1 i=2
synchronized threadName=Thread-1 i=3
synchronized threadName=Thread-1 i=4
synchronized threadName=Thread-1 i=5
synchronized threadName=Thread-1 i=6
synchronized threadName=Thread-1 i=7
synchronized threadName=Thread-1 i=8
synchronized threadName=Thread-1 i=9
synchronized threadName=Thread-1 i=10
nosynchronized threadName=Thread-0 i=3
nosynchronized threadName=Thread-0 i=4
nosynchronized threadName=Thread-0 i=5
nosynchronized threadName=Thread-0 i=6
nosynchronized threadName=Thread-0 i=7
nosynchronized threadName=Thread-0 i=8
nosynchronized threadName=Thread-0 i=9
nosynchronized threadName=Thread-0 i=10

synchronized threadName=Thread-0 i=1
synchronized threadName=Thread-0 i=2
synchronized threadName=Thread-0 i=3
synchronized threadName=Thread-0 i=4
synchronized threadName=Thread-0 i=5
synchronized threadName=Thread-0 i=6
synchronized threadName=Thread-0 i=7
synchronized threadName=Thread-0 i=8
synchronized threadName=Thread-0 i=9
synchronized threadName=Thread-0 i=10

3.5施用原子类举行i 操作  

  除了synchronized能够兑现在i 操作时的共同外,AtomicInteger原子类也足以完结。

  原子类型是不可分割的全部未有别的线程能够中断或检查正在原子操作的变量。

皇冠手机网 13皇冠手机网 14

 

  使用原子类的incrementAndGet()方法就可以兑现同台


 

3.4用到原子类实行操作

public class MyThread implements Runnable {
    private AtomicInteger count = new AtomicInteger();
    @Override
    public void run() {
        for(int i=0;i<1000;i  ){
            System.out.println(count.incrementAndGet());
        }
    } 
}


public class Run { 
    public static void main(String[] args) throws InterruptedException { 
        MyThread mt = new MyThread();
        Thread  t1 = new Thread(mt);
        t1.start();
        Thread  t2 = new Thread(mt);
        t2.start();
        Thread  t3 = new Thread(mt);
        t3.start();
        Thread  t4 = new Thread(mt);
        t4.start();
        Thread  t5 = new Thread(mt);
        t5.start();
    } 
} 

运行结果:同步的

1.2实例变量非线程安全

  假如八个线程同一时候做客三个目的的实例变量,则只怕会冒出“非线程安全主题材料”。

  有多少个实例变量大概会油然则生交叉的状态,假如只有二个实例变量时也许会现身覆盖的处境。

  若想消除非线程安全难题,必要在对实例变量操作的诀窍上加synchronized关键字做修饰。


 

本文由澳门皇冠金沙网站发布于编辑程序,转载请注明出处:皇冠手机网对象及变量的并发访问,第二章总结