Java多线程--synchronized(二)

synchronized 同步语句块

synchronized方法的缺点

直接在方法上加synchronized关键字在某些情况下存在弊端,比如线程A调用同步方法执行长时间任务,那么其他线程将会等待很长时间。

package ch02.test3;
/*
    synchronized 同步代码块
 */
public class Task {
    private String getData1;
    private String getData2;
    public synchronized void doLongTimeTask() {
        try{
            System.out.println("begin task");
            Thread.sleep(3000);
            String tmpGetData1 = "长时间执行任务返回结果1 threadname=" + Thread.currentThread().getName();
            String tmpGetData2 = "长时间执行任务返回结果2 threadname=" + Thread.currentThread().getName();
            getData1 = tmpGetData1;
            getData2 = tmpGetData2;
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class CommonUtils {
    public static long beginTime1;
    public static long endTime1;
    public static long beginTime2;
    public static long endTime2;
}

class MyThread1 extends Thread {
    private Task task;

    public MyThread1(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        super.run();
        CommonUtils.beginTime1 = System.currentTimeMillis();
        this.task.doLongTimeTask();
        CommonUtils.endTime1 = System.currentTimeMillis();
    }
}

class MyThread2 extends Thread {
    private Task task;

    public MyThread2(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        super.run();
        CommonUtils.beginTime2 = System.currentTimeMillis();
        this.task.doLongTimeTask();
        CommonUtils.endTime2 = System.currentTimeMillis();
    }
}

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

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long beginTime = Math.min(CommonUtils.beginTime1, CommonUtils.beginTime2);
        long endTime = Math.max(CommonUtils.endTime1, CommonUtils.endTime2);
        System.out.println("总耗时:"+ (endTime - beginTime) / 1000 + "s");
    }
}

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
总耗时:6s

synchronized同步代码块的使用

修改doLongTimeTask()方法,去掉方法上的synchronized,在其中添加同步代码块:

public void doLongTimeTask() {
        try{
            System.out.println("begin task");
            Thread.sleep(3000);
            String tmpGetData1 = "长时间执行任务返回结果1 threadname=" + Thread.currentThread().getName();
            String tmpGetData2 = "长时间执行任务返回结果2 threadname=" + Thread.currentThread().getName();
            synchronized (this) {
                getData1 = tmpGetData1;
                getData2 = tmpGetData2;
            }
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

output:

begin task
begin task
长时间执行任务返回结果1 threadname=Thread-1
长时间执行任务返回结果2 threadname=Thread-0
end task
长时间执行任务返回结果1 threadname=Thread-0
长时间执行任务返回结果2 threadname=Thread-0
end task
总耗时:3s

当一个线程访问同步代码块时,其他线程仍然可以访问该对象的非同步代码块
方法中线程在synchronized (this) 同步代码块是同步的,不在同步代码块的部分是异步的

  • 和synchronized方法相似,当一个线程访问anyObject对象的synchronized(this)同步代码块时,其他线程中所有同步代码块的访问将被阻塞,说明synchronized使用的“对象监视器”是一个。

小结

  1. synchronized同步方法
    1.1 同一时间只能有一个线程执行synchronized同步方法。
    1.2 对同一对象的所有其他synchronized同步方法和synchronized(this)同步代码块调用呈阻塞状态。
  2. synchronized(this)同步代码块同步代码块
    1.1 同一时间只能有一个线程执行synchronized(this)同步代码块。
    1.2 对同一对象的所有其他synchronized同步方法和synchronized(this)同步代码块调用呈阻塞状态。
posted @ 2020-09-11 10:49  来一块小饼干  阅读(125)  评论(0编辑  收藏  举报