使用synchronized虽然能够避免不同步的现象出现,但是也会出现弊端,比如代码执行时间过长,那么其他线程就必须等待该线程执行完毕释放锁之后才能拿到锁。

面对这种问题可以使用同步代码块来解决。

2.2.1synchronized方法的弊端:

任务类:

public class Task {
    private String getData1;
    private String getData2;
    synchronized public 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) {
            e.printStackTrace();
        }
    }
}

工具类:

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

线程代码1:

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

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

线程代码2:

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

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

执行代码:

public class Main {
    public static void main(String[] args) {
        Task task = new Task();
        Thread1 thread1 = new Thread1(task);
        thread1.start();
        Thread2 thread2 = new Thread2(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);

    }
}

执行结果:

从结果看这样运行一段代码耗时严重,解决这样的问题可以使用synchronized同步代码块。

2.2.2synchronized同步代码块的使用:

两个线程同时访问同一个对象的synchronized(this)同步代码块时,在代码运行期间只能有一个线程执行该段代码块,另一个线程必须等待当前线程完成执行才能够执行该段代码。

模块业务类:

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

线程代码1:

public class Thread3 extends Thread {
    private ObjectService objectService;
    public Thread3(ObjectService objectService) {
        this.objectService = objectService;
    }

    @Override
    public void run() {
        objectService.serviceMethod();
    }
}

线程代码2:

public class Thread4 extends Thread {
    private ObjectService objectService;
    public Thread4(ObjectService objectService) {
        this.objectService = objectService;
    }

    @Override
    public void run() {
        objectService.serviceMethod();
    }
}

执行代码:

public class Main {
    public static void main(String[] args) {
        ObjectService objectService = new ObjectService();
        Thread3 thread3 = new Thread3(objectService);
        thread3.setName("a");
        thread3.start();
        Thread4 thread4 = new Thread4(objectService);
        thread4.setName("b");
        thread4.start();
    }
}

执行结果:

这样使用同步代码块,并没有使代码的效率提高,执行的效果还是同步执行的。下面的示例中解决synchronized同步代码块执行效率低的问题。

2.2.3用同步代码块解决同步方法的弊端:

任务类:

public class DoLongTimeTask1 {
    private String getData1;
    private String getData2;
    public void doLongTimeTask() {
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            String privateData1 = "长时间处理任务后从后台远程返回的值1 threadName = "
                    + Thread.currentThread().getName();
            String privateData2 = "长时间处理任务后从后台远程返回的值2 threadName = "
                    + Thread.currentThread().getName();
            synchronized (this) {
                getData1 = privateData1;
                getData2 = privateData2;
            }
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程代码1:

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

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

线程代码2:

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

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

执行代码:

public class Main {
    public static void main(String[] args) {
        Task task = new Task();
        Thread1 thread1 = new Thread1(task);
        thread1.start();
        Thread2 thread2 = new Thread2(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);

    }
}

执行结果:

从上述可知当一个线程访问object中的synchronized同步代码块时,其他线程可以访问该object对象中非synchronized(this)同步代码块的内容。

时间缩短,且运行效率加快,而且能够保持synchronized是同步的且当前线程持有锁。下面的示例进行验证。

2.2.4一半异步,一半同步:

事先说明:不在synchronized块中的代码使异步的,在synchronized中的代码是同步的。

任务代码:

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

线程代码1:

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

线程代码2:

public class Thread6 extends Thread {
    private Task1 task;
    public Thread6(Task1 task) {
        this.task = task;
    }

    @Override
    public void run() {
        task.doLongTimeTask();
    }
}

执行代码:

public class Main {
    public static void main(String[] args) {
        Task1 task = new Task1();
        Thread5 thread5 = new Thread5(task);
        thread5.start();
        Thread6 thread6 = new Thread6(task);
        thread6.start();

    }
}

执行结果(左边为非同步,右边为同步):

可以看出在同步代码块中的代码是同步运行的,而在非同步代码块中的代码是异步运行的。

2.2.5synchronized代码块间的同步性:

若一个线程访问了object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有的其他synchronized(this)同步代码块的访问将被阻塞。

这个现象表明了:synchronized使用的是一个对象监视器。

 

 

 

版权声明:本文为lilinzhiyu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:http://www.cnblogs.com/lilinzhiyu/p/7994275.html