多線程(二)

1.synchronized鎖重入java

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("service2");
    }
}
//線程類
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();
    }
/*
output:
service1
service2
service3
*/
}

總結:本身能夠再次獲取本身的內部鎖.也支持在父子類繼承的環境中dom

2.出現異常,鎖自動釋放異步

public class Service {
    synchronized public void testMethod(){
        if(Thread.currentThread().getName().equals("a")){
            System.out.println("ThreadName="+Thread.currentThread().getName()
            +" run beginTime="+System.currentTimeMillis());
            int i=1;
            while(i==1){
                if((""+Math.random()).substring(0,8).equals("0.123456")){
                    System.out.println("ThreadName="+Thread.currentThread().getName()
                    +" run exceptionTime="+System.currentTimeMillis());
                    Integer.parseInt("a");
                }
            }
        }else{
            System.out.println("Thread B runt Time="+System.currentTimeMillis());
        }
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            Service service=new Service();
            ThreadA a=new ThreadA(service);
            a.setName("a");
            a.start();
            Thread.sleep(500);
            ThreadB b=new ThreadB(service);
            b.setName("b");
            b.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
/*output:
ThreadName=a run beginTime=1523554493390
ThreadName=a run exceptionTime=1523554494218
//a報錯,鎖自動釋放
Thread B runt Time=1523554494219
Exception in thread "a" java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at us.codecraft.dxc.Service.testMethod(Service.java:16)
    at us.codecraft.dxc.ThreadA.run(ThreadA.java:36)
*/
}

3.同步不具備繼承性ide

//父類
public class Main {
    synchronized public void serviceMethod(){
        try {
            System.out.println("int main 下一步 sleep begin threadName="
                    +Thread.currentThread().getName()+" time="+System.currentTimeMillis()
            );
            Thread.sleep(5000);
            System.out.println("int main 下一步 sleep end threadName="+
            Thread.currentThread().getName()+" time="+
                    System.currentTimeMillis()
            );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//子類
public class Sub extends Main{
    @Override
    public void serviceMethod() {
        try {
            System.out.println("int sub 下一步 sleep begin threadName="
                    +Thread.currentThread().getName()+" time="+System.currentTimeMillis()
            );
            Thread.sleep(5000);
            System.out.println("int sub 下一步 sleep end threadName="+
                    Thread.currentThread().getName()+" time="+
                    System.currentTimeMillis()
            );
            super.serviceMethod();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//線程A
public class ThreadA extends Thread{
    private Sub sub;
    public ThreadA(Sub sub){
        super();
        this.sub=sub;
    }

    @Override
    public void run() {
        sub.serviceMethod();
    }
}
//線程B
public class ThreadB extends Thread{
    private Sub sub;
    public ThreadB(Sub sub){
        super();
        this.sub=sub;
    }

    @Override
    public void run() {
        sub.serviceMethod();
    }
}
public class Test {
    public static void main(String[] args) {
        Sub subRef=new Sub();
        ThreadA a=new ThreadA(subRef);
        a.setName("A");
        a.start();
        ThreadB b=new ThreadB(subRef);
        b.setName("B");
        b.start();
    }
/*output:
int sub 下一步 sleep begin threadName=B time=1523556610729
int sub 下一步 sleep begin threadName=A time=1523556610729
int sub 下一步 sleep end threadName=A time=1523556615729
int sub 下一步 sleep end threadName=B time=1523556615729
int main 下一步 sleep begin threadName=A time=1523556615729
int main 下一步 sleep end threadName=A time=1523556620730
int main 下一步 sleep begin threadName=B time=1523556620730
int main 下一步 sleep end threadName=B time=1523556625730
*/
}

4.synchronized的弊端:測試

package us.codecraft.dxc;

/**
 * Created by Administrator on 2018/4/13.
 */
public class Task {
    private String getDate1;
    private String getDate2;
    public synchronized void doLongTimeTask(){
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            getDate1="長時間處理任務後從遠程返回值1 threadName="+Thread.currentThread().getName();
            getDate2="長時間處理任務後從遠程返回值2 threadName="+Thread.currentThread().getName();
            System.out.println(getDate1);
            System.out.println(getDate2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class CommonUtils {
    public static long beginTime1;
    public static long endTime1;
    public static long beginTime2;
    public static long endTime2;

}
public class MyThread1 extends Thread{
    private Task task;
    public MyThread1(Task task){
        super();
        this.task=task;
    }

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

    @Override
    public void run() {
        super.run();
        CommonUtils.beginTime2=System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime2=System.currentTimeMillis();
    }
}
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();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long beginTime=CommonUtils.beginTime1;
        if(CommonUtils.beginTime2<CommonUtils.beginTime1){
            beginTime=CommonUtils.beginTime2;
        }
        long endTime=CommonUtils.endTime1;
        if (CommonUtils.endTime2>CommonUtils.endTime1) {
            endTime = CommonUtils.endTime2;
        }
        System.out.println("耗時"+((endTime-beginTime)/1000));

    }
/*output:
begin task
長時間處理任務後從遠程返回值1 threadName=Thread-0
長時間處理任務後從遠程返回值2 threadName=Thread-0
end task
begin task
長時間處理任務後從遠程返回值1 threadName=Thread-1
長時間處理任務後從遠程返回值2 threadName=Thread-1
end task
耗時6*/
}

一段時間內只能有一個線程被執行,另外一個線程必須等待當前線程執行完代碼之後才能執行該代碼塊this

解決方法:使用同步代碼塊線程

public class Task {
    private String getDate1;
    private String getDate2;
    public void doLongTimeTask(){
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            synchronized (this){
            getDate1="長時間處理任務後從遠程返回值1 threadName="+Thread.currentThread().getName();
            getDate2="長時間處理任務後從遠程返回值2 threadName="+Thread.currentThread().getName();
            }
            System.out.println(getDate1);
            System.out.println(getDate2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
/**output:
begin task
begin task
長時間處理任務後從遠程返回值1 threadName=t1
長時間處理任務後從遠程返回值2 threadName=t1
end task
長時間處理任務後從遠程返回值1 threadName=t2
長時間處理任務後從遠程返回值2 threadName=t2
end task
耗時3
/
}

5.多個線程調用同一個對象中的不一樣名稱的synchronized同步方法或者synchronized(this)同步代碼塊時,調用的效果是按照順序執行,也就是同步的,阻塞的code

synchronized同步方法和synchronized(this)同步代碼塊分別有兩種做用:orm

對其餘synchronized同步方法或者synchronized(this)同步代碼塊調用呈阻塞狀態對象

同一時間只有一個線程能夠執行或者synchronized()同步方法或者synchronized(this)同步代碼中的代碼

6.將任意對象做爲對象監視器

public class Service {
    private String password;
    private String username;
    String anyString =new String();
    public void setUsernamePass(String username,String password){
        try {
            synchronized (anyString) {
                System.out.println("線程名爲:" + Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "進入同步塊");
                Thread.sleep(3000);
                this.username = username;
                this.password=password;
                System.out.println("線程名爲:" + Thread.currentThread().getName() + "在" +
                        System.currentTimeMillis() + "離開同步塊");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service){
        super();
        this.service=service;
    }

    @Override
    public void run() {
        service.setUsernamePass("a","aa");
    }
}
public class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service){
        super();
        this.service=service;
    }

    @Override
    public void run() {
        service.setUsernamePass("b","bb");
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service=new Service();
        ThreadA threadA=new ThreadA(service);
        threadA.setName("A");
        threadA.start();
        ThreadB threadB=new ThreadB(service);
        threadB.setName("B");
        threadB.start();
    }
/*output:
線程名爲:A在1522229473958進入同步塊
線程名爲:A在1522229476969離開同步塊
線程名爲:B在1522229476969進入同步塊
線程名爲:B在1522229479980離開同步塊
//同步,阻塞,先由A進入,再由B進入
*/
}

總結:咱們能夠看出synchronized(非this對象)若是是公共資源(調用同一個類對象,兩個線程影響同一個anyString)就是實現同步,阻塞功能.由此咱們能夠得出,若是synchronized(非this對象)鎖住的是私有變量的話,就能夠實現異步,非阻塞的功能,下面咱們來實驗一下.

public class Service {
    private String password;
    private String username;
    public void setUsernamePass(String username,String password){
        try {
            String anyString =new String();//將變量設置爲局部變量
            synchronized (anyString) {
                System.out.println("線程名爲:" + Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "進入同步塊");
                Thread.sleep(3000);
                this.username = username;
                this.password=password;
                System.out.println("線程名爲:" + Thread.currentThread().getName() + "在" +
                        System.currentTimeMillis() + "離開同步塊");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
/*output:
線程名爲:A在1522229832397進入同步塊
線程名爲:B在1522229832397進入同步塊
線程名爲:A在1522229835408離開同步塊
線程名爲:B在1522229835408離開同步塊
//兩個線程同時進入方法,非阻塞,異步
*/
}

總結:大大提升了運行效率.

7.靜態同步synchronized方法與synchronized(class)代碼塊

synchronized應用在static靜態方法上,這樣是對當前的*.class文件對應的class類進行持鎖.

例子:

public class Service {
    synchronized public static void printA(){
        try {
            System.out.println("線程名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入printA");
            Thread.sleep(3000);
            System.out.println("線程名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void printB(){
        System.out.println("線程名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入printB");
        System.out.println("線程名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開printB");
    }
}
public class ThreadA extends Thread{
    @Override
    public void run() {
        Service.printA();
    }
}
public class ThreadB extends Thread{
    @Override
    public void run() {
        Service.printB();
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadA a =new ThreadA();
        a.setName("a");
        a.start();
        ThreadB b=new ThreadB();
        b.setName("b");
        b.start();
    }
/*output:
線程名稱爲:a在1515601919412進入printA
線程名稱爲:a在1515601922412離開printA
線程名稱爲:b在1515601922412進入printB
線程名稱爲:b在1515601922412離開printB
*/
}

總結:synchronized關鍵字加到static靜態方法上是給class類上鎖,而synchronized關鍵字加到非static靜態方法上是給對象加鎖

相關文章
相關標籤/搜索