多线程(二)

1.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("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
*/
}

总结:自己可以再次获取自己的内部锁.也支持在父子类继承的环境中

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.同步不具有继承性

//父类
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*/
}

一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完代码以后才能执行该代码块

解决方法:使用同步代码块

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)同步代码块时,调用的效果是按照顺序执行,也就是同步的,阻塞的

synchronized同步方法和synchronized(this)同步代码块分别有两种作用:

对其他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静态方法上是给对象加锁

转载于:https://my.oschina.net/u/3744319/blog/1602401

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值