四、java多線程核心技術——synchronized同步方法與synchronized同步快


一、synchronized同步方法

論:“線程安全”與“非線程安全”是多線程的經典問題。synchronized()方法就是解決非線程安全的。

1、方法內的變量為線程安全

public void addI(String username) {
        try {
            int num = 0;     \\方法內的變量為線程安全 if (username.equals("a")) {
                num = 100;
                System.out.println("a set over!");
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println("b set over!");
            }
            System.out.println(username + " num=" + num);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

2、實例變量非線程安全

public class HasSelfPrivateNum {
    private int num = 0;    \\實例變量非線程安全 public void addI(String username) {
        try {
            if (username.equals("a")) {
                num = 100;
                System.out.println("a set over!");
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println("b set over!");
            }
            System.out.println(username + " num=" + num);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

解決方法: 方法前加synchronized關鍵字。

public class HasSelfPrivateNum {

    private int num = 0;

    synchronized public void addI(String username) {
       ..............
    }

}

3、多個對象多個鎖

HasSelfPrivateNum.java

public class HasSelfPrivateNum {

    private int num = 0;

    synchronized public void addI(String username) {
        try {
            if (username.equals("a")) {
                num = 100;
                System.out.println("a set over!");
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println("b set over!");
            }
            System.out.println(username + " num=" + num);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

ThreadA

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

    private HasSelfPrivateNum numRef;

    public ThreadB(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }

}

RUN

public class Run {

    public static void main(String[] args) {

        HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
        HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();

        ThreadA athread = new ThreadA(numRef1);
        athread.start();

        ThreadB bthread = new ThreadB(numRef2);
        bthread.start();

    }

}

結果:創建了2個業務實例,產生2個鎖,所以運行結果是異步的。同步為synchronized  異步:asynchronized

4、synchronized 鎖重入

                   當一個線程得到一個對象鎖時,再次請求該對象鎖時是可以再次得到該對象的鎖的。繼承關系也可重入鎖。

                   當一個線程執行發生異常時,其持有的鎖會自動釋放。

                   同步不具有繼承性。的在子類方法中添加synchronized的關鍵字。

public class HasSelfPrivateNum {
    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");
    }
}
HasSelfPrivateNum.java
public class mYThread extends Thread {
    @Override
    public void run() {
        HasSelfPrivateNum hspn=new HasSelfPrivateNum();
        hspn.service1();    
    }
   public static void main(String[] args) {
       mYThread mYThread=new mYThread();
       mYThread.start();
 }
}
mYThread.java

 二、synchronized同步快

    synchronized同步方法持有鎖后,如果長時間不釋放,那另一個線程就必須長時間等待。。這種情況下synchronized同步快來解決

使用方法如圖:

                1、synchronized同步快之間具有同步性,當線程訪問object的一個  synchronized(this)同步代碼塊時,其他線程對同一個object對象中所有其他的

synchronized(this)同步代碼塊的訪問會被阻塞。

                2、synchronized(this)同步代碼塊是鎖定當前對象的。

1、synchronized同步快解決同步方法效率低得弊端

public class Task {

    private String getData1;
    private String getData2;

    public synchronized void doLongTimeTask() {
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            getData1 = "長時間處理任務后從遠程返回的值1 threadName="
                    + Thread.currentThread().getName();
            getData2 = "長時間處理任務后從遠程返回的值2 threadName="
                    + Thread.currentThread().getName();
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
Task
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();
    }

}
MyThread1
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();
    }

}
MyThread2
public class CommonUtils {

    public static long beginTime1;
    public static long endTime1;

    public static long beginTime2;
    public static long endTime2;
}
CommonUtils
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));
    }
}
Run

修改Task

public class Task {

    private String getData1;
    private String getData2;

    public void doLongTimeTask() {
        try {
            System.out.println("begin task");
            Thread.sleep(3000);

            String privateGetData1 = "長時間處理任務后從遠程返回的值1 threadName="
                    + Thread.currentThread().getName();
            String privateGetData2 = "長時間處理任務后從遠程返回的值2 threadName="
                    + Thread.currentThread().getName();

            synchronized (this) {
                getData1 = privateGetData1;
                getData2 = privateGetData2;
            }
            
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM